主要记录我在《嗨翻C语言》中记录的知识点,以备用时参考。
C语言入门
- gcc(GNU编译器套件--GNU Compiler Collection)是个C编译器。
Linux 直接存在
Mac 可使用Xcode
Windows 可用Cygwin(模拟Unix环境)或MinGw(仅运行程序)
- 计算机仅理解机器代码-->二进制流。
-
int main()
函数是程序中所有代码的起点。 - 若要检查程序的退出状态(通常是int main()函数的返回值):
Windows下可在命令行输入 echo %ErrorLevel%
Linux或Mac下输入 echo $?
Note:Cygwin中输入 echo $?
- 一条命令解决编译和运行,利用
&&
即可,eg:
gcc test.c -o test **&&** ./test
- 在类Unix(Linux/Mac)操作系统中,运行程序必须指定程序所在目录,除非该目录位于PATH环境变量中。
- C语言中,0为假,其他情况均为真。
- & | 与 && ||的异同:
同:都携带两个条件
异:&&和||,在特定条件下可以跳过第二个条件。
&和|必须且总是计算两个条件;而且可以对数字的某一位进行布尔运算。
example1: A && B,若A为假,则B不必被计算;A & B,无论A真或假,B都必须被计算;
example2: A || B,若A为真,则B不必被计算;A | B,无论A真或假,B都必须被计算。
- 部分函数、关键字、语句举例:
-
puts()
在命令提示符或终端显示字符串。 -
scanf()
从标准输入读取数据;可输入多个字段;可输入结构化数据。
int x;
scanf("%d", &x);//fscanf(stdin, "%d", &x)
它在读取数据时,遇到空格就停止,除非多个格式化占位符,eg:
#include <stdio.h>
int main()
{
char msg[21];
char phone[12];
scanf("%20s %11s", msg, phone);
printf("输出\n");
printf("%s---------%s\n", msg, phone);
printf("%li %li\n", sizeof (msg), sizeof (phone));
msg[2] = '\0';
phone[7] = '\0';
printf("%s---------%s\n", msg, phone);
return 0;
}
运行结果如下:
Liana 19996999999
输出
Liana---------19996999999
21 12
Li---------1999699
*example1 ---- scanf()获取数: *
int num = -1;
scanf("%i", &num); /*scanf()需要的是变量地址*/
*example2 ---- scanf()获取字符数组: *
char ex[11];
scanf("%10s", ex);
/ *ex字符数组设置大小为11,但scanf获取的长度至多为10,
*因为C语言中存在着标志字符串结束的空字符'\0',
*与fgets()函数获取字符数组内容时有区别。* /
-
fgets(变量, sizeof(变量), stdin)
,eg:
#include <stdio.h>
int main()
{
char msg[10];
fgets(msg, 10, stdin);
//char *msg = malloc(sizeof(char)*10);
//fgets(msg, 10, stdin);
printf("输出\n");
printf("%s---------", msg);
printf("%li\n", sizeof (msg));
return 0;
}
运行结果如下:
Liana
输出
Liana
---------10
-
printf()
显示格式化输出;把数据发送到标准输出。
printf("i like cakes.\n")
//fprintf(stdout, "i like cakes.\n");
Note: <stdio.h> 包含能在终端读写数据的接口。
-
continue
可以跳过循环体其余部分,回到循环开始(即永远跳至循环条件处)。
example1 ---- while循环体:
/ *先判断条件,条件满足则再执行语句块
*重复上述步骤 * /
int i = 0;
while(i < 8)
{
printf("%d ", i);
if(i == 2)
{
i += 2;
continue;
}
++i;
}
这段代码输出结果如下:
0 1 2 4 5 6 7
example2 ---- do-while循环体:
/* Loop:先执行一次语句块判断条件,再判断条件是否,满足则重复上述步骤 */
int i = 0;
do {
++i;
printf("%d ", i);
if( i == 3)
{
i += 2;
continue;
}
} while(i < 7);
这段代码输出结果如下:
1 2 3 6 7
-
break
可以跳出循环语句块和switch语句块,但不能从if语句块中跳出。
存储器和指针(含字符串)
-
总线错误:程序不能更新那一块存储空间。
段错误abort trap <-- 缓冲区溢出 - C语言中,用双引号定义的字符串叫做字符串字面值(string literal),是常量;而字符数组不是。
example :
char a[] = "hello";
- 指针可以避免副本、共享数据。
指针只是一个保存存储器地址的变量,是进程存储器中真实编号的地址。
*
可以读取(作为右值)或设置存储器地址的内容(作为左值)。 - 赋值语句也有返回值。
example 1 ---- 赋值:
int x, y;
y = (x = 4) /*等价于 y = x = 4;*/
//此时y的值为4
example 2 ---- 判等:
int x = 2;
int y = (x == 2);
//此时y的值为1
- 引用
int x = 4;
int *a = &x;//a指向变量x的地址
int k = *a;//*a作为右值,可以读出a上存储的地址(x的地址)中存储的值(x的值)
//k = 4
-
sizeof()
是运算符,而非函数。
程序在编译时期将sizeof编译为一串指令,确定存储空间的大小,从而计算sizeof()
的值。
它在计算字符串字面值长度时会包含空字符\0的长度,eg :
int k = sizeof ("haha");
printf("%d", k);
此处结果为:
5
- 数组变量也是个地址,eg :
int x = 3;
int a[2] = {3, 4};
printf("%p , %p\n", &x, a);
//%p 可用于格式化地址(十六进制)
此处会打印两个十六进制地址值,eg:
0x7ffe11d245dc , 0x7ffe11d245e0
- 计算机会为每个进程分配一个简版存储器(存储器是进程的) 。
函数中声明的变量通常保存于栈中,在main()
函数外部声明的变量保存于全局变量中。
栈区 <-存局部变量
堆区 <-存全局变量
全局区
常量段(只读存储器) <-存字符串常量
代码段
- 将指针强制转化为一般数字,eg :
int x = 4;
int *p = &x;
long a = (long) p;
- 修改const修饰的变量,编译期会报错。
- 关于数组的相关计数,
位置------------------从1开始
索引、下标-------------从0 开始
- 数组可以当指针用,
将数组传递给函数时,函数会将其作为指针变量。
把数组变量传给指针,会发生退化(长度将未知),
example1:
#include <stdio.h>
void fun(char msg[])//实际为指针变量
{
printf("%s\n", msg);
printf("%li", sizeof (msg));//这里计算的大小是指针变量的大小,而非字符串的大小。
}
int main()
{
char *s="i am a cute, smart girl.";
fun(s);
printf("\n");
char ss[] ="i am a cute, smart girl.";
fun(ss);
return 0;
}
该程序运行结果如下:
i am a cute, smart girl.
8
i am a cute, smart girl.
8
example2:
#include <stdio.h>
int main()
{
char *s1="i am a cute, smart girl.";
char ss1[] ="i am a cute, smart girl.";
printf("%s\n", s1);
printf("%li\n", sizeof (s1));
printf("%s\n", ss1);
printf("%li", sizeof (ss1));
return 0;
}
该程序运行结果如下:
i am a cute, smart girl.
8
i am a cute, smart girl.
25
创建小工具
-
sed
流编辑器(stream editor) ---- 搜索、替换文本 -
标准输入/输出/错误
标准输入/输出/错误.png - 重定向
- 默认情况下,标准输出会发送到显示器。可以借助
>
将标准输出重定向到文件。 - 默认情况下, 标注输入来从键盘读取数据。可以借助
<
将标准输出重定向到文件。 - 标准错误用于输出错误消息。可以借助
2>
重定向标准错误。
Note:重定向最多可以写两个文件, 一个标准输出,一个标准错误。
要同时输出多个文件,则需要创建自己的数据流,例如fopen()。
eg:
#include <stdio.h>
int main()
{
char word[10];
int i = 0;
while(scanf("%9s", word) == 1)
{
++i;
if(i % 2)
fprintf(stdout, "%s\n", word);
else
fprintf(stderr, "%s\n", word);
}
return 0;
}
//secret.txt的内容如下:
//THE I GIRL'S AM NAME VERY IS CUTE LIANA.
在该程序中,将标准输入重定向到文件secret.txt,并将标准输出、标准错误分别重定向到message.txt和message2.txt中:
gcc main.c -o test
./test < secret.txt > message.txt 2> message2.txt
运行结果如下:
//message.txt 的内容
THE
GIRL'S
NAME
IS
LIANA.
//message2.txt 的内容
I
AM
VERY
CUTE
4.管道pipe |
能连接一个进程的标准输入与另一个进程的标准输出
A | B
系统同时运行A和B两个程序,并将A的输出变成B的输入
流水线:一连串相连的进程。
当管道连接多个进程时, < 会把文件内容发送到流水线中第一个进程的标准输入, > 会捕获流水线中最后一个进程的标准输出。
- 创建数据流/C语言中文件的使用
FILE *file = fopen(文件路径, 模式);//打开数据流
fclose(file);//关闭数据流
一个进程能拥有的数据流是有限的,所以用完应及时关闭。
模式
w(写文件,write) r(读文件,read) a(在文件末尾追加,append)
FILE *infile = fopen("input.txt", "r");
FILE *outfile = fopen("output.txt", "w");
fprintf(outfile, "你很%s", "好看");
char sentence[20];
fscanf(infile, "%19s", sentence);
fclose(infile);
fclose(outfile);
- 命令行小工具
ps -ae//显示所有进程,包括后台运行的进程
tail -t 文件名//持续显示文件末尾新添加的数据
- 修改程序工作方式
- 对于GUI程序:修改程序首选项
- 对于命令行程序:传递命令行参数
-
main函数
的两种形式int main()
-
int main(int argc, char *argv[])
其中argv[0]为待运行程序的名字,argc记录的是数组中元素的个数
Note:在处理上述函数的参数时,可以由库代劳,使用时需要包含#include <unistd.h>。
getopt()每次调用都会返回命令行中下一个参数,optarg变量指向选项后的那个参数,optind保存该函数从命令行读取了几个选项。
-
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char *delivery = "";
int thick = 0;
int ch;
while ((ch = getopt(argc, argv, "d:t")) != EOF/*-1*/)
{
switch (ch)
{
case 'd':
delivery = optarg;
break;
case 't':
thick = 1;
break;
default:
fprintf(stderr, "Unknown option: '%s'\n", optarg);
return 1;
}
}
argc -= optind;
argv += optind;
if(thick) puts("Thick crust.");
if(delivery[0]) printf("To be delivered %s. \n", delivery);
puts("Ingredients: ");
for (int count = 0; count != argc; ++count)
puts(argv[count]);
return 0;
}
该程序结果如下:
gcc main.c -o order_pizza
./order_pizza Anchovies
Ingredients:
Anchovies
./order_pizza Anchovies Pineapple
Ingredients:
Anchovies
Pineapple
./order_pizza -d now Anchovies Pineapple
To be delivered now.
Ingredients:
Anchovies
Pineapple
./order_pizza -d now -t Anchovies Pineapple
Thick crust.
To be delivered now.
Ingredients:
Anchovies
Pineapple
./order_pizza -d
./order_pizza: option requires an argument -- 'd'
Unknown option: '(null)'