目录
第1章 初始C语言
- 编译器和连接器的作用如下图。
第2章 C语言概述
略
第3章 数据和C
- sizeof()是C语言的内置运算符,以字节为单位给出指定类型的大小。
第4章 字符串和格式化输入/输出
- scanf()在读取字符串时遇到第一个空白(空格、制表符、换行符)时就不再读取输入。
- scanf("%c",&ch)从输入的第一个字符开始读取,scanf(" %c",&ch)从输入的第一个非空白字符开始读取。
- 使用%s读取字符串"-13.45e12# 0",scanf()会读取-13.45e12#,并停在空格处,空格将被留在输入中作为下一次输入的首字符。
- const关键字限定一个变量为只读,如cosnt int MONTHS = 12;
第5章 运算符、表达式和语句
- 多重赋值时,顺序从右向左如:
int a,b,c;
a = b = c = 1; - "/“和”%"运算采用趋0截断。
第6章 C控制语句:循环
- 在比较浮点数时,尽量只使用"<“和”>",因为浮点数的舍入误差会导致逻辑上相等的两个数不相等。
- 逗号运算符把两个表达式连接成一个表达式,并保证最左边的表达式最先求值。
- scanf()的返回值是成功赋值的变量的个数(int)。
第7章 C控制语句:分支和跳转
- switch在圆括号中的测试表达式的值应该是一个整数值(包括char类型)。case标签必须是整数类型)包括char类型)的常量或整型常量表达式
- 尽量不使用"goto"语句,但是,C程序员可以接受一种goto的用法——出现问题时从一组嵌套循 环中跳出(一条break语句只能跳出当前循环)。如下代码示例:
while (funct > 0){
for (i = 1, i <= 100; i++){
for (j = 1; j <= 50; j++){
其他语句;
if(问题)
goto help;
其他语句;
}
其他语句;
}
其他语句;
}
其他语句;
help: 语句;
第8章 字符输入/输出和输入验证
- EOF(end of file),用getchar()和scanf()函数检测到文件结尾时会返回EOF(在窗口中可以ctrl+z再按回车)。EOF定义在stdio.h中。
#define EOF -1
- 许多操作系统都提供重定向,允许用文件代替键盘 输入,用文件代替显示器输出。
第9章 函数
- scanf("%*s")可以用来跳至下一个空白字符。
- int* a时,类型(int)和*以及*和a(变量名)之间的空格可有可无。
- 在函数的声明中可以省略参数名,但是定义中不能省略参数名。
int sum(int,int); //函数声明
int sum(int a,int b){ //函数定义
return a+b;
}
第10章 数组和指针
- C不会检查数组的下标是否越界(负数或超过下标上限)。
- 既能使用指针表示数组名,也可以用数组名表示指针。
- 关于函数的形参,有一点要注意。只有在函数原型或函数定义头中, 才可以用int ar[]代替int * ar,即
int sum(int ar[], int n);//int *ar形式和int ar[]形式都表示ar是一个指向int的指针。
- 把const数据或非const 数据的地址初始化为指向const的指针或为其赋值是合法的。
然而,只能把非const数据的地址赋给普通指针。(即const数据不能赋值给普通指针)这个规则非常合理。否则,通过指针就能改变const数组中的数据。(C中只会警告,C++中会报错) - 可以声明并初始化一个不能指向别处的 指针,关键是const的位置:
double rates[5] = {88.99, 100.12, 59.45, 183.11, 340.5};
double * const pc = rates; //pc指向数组的开始,可以修改pc[0](即*pc)的值,但不能再指向别处
//const double * pc = rates; //const放前面则,pc可以指向别处,但不能修改其值
//const double * const pc = rates; //pc即不能修改指向地址上的值也不能指向别处(只能读)
- 因为[]的优先级高于*,因此下面两种写法含义不同
int (* pz)[2]; // pz指向一个内含两个int类型值的数组
int * pax[2]; // pax是一个内含两个指针元素的数组,每个元素都指 向int的指针
用途:1.如果函数的形参是一个多维数组的话,用int (* pz)[2]
或int pz[][2]
这种方式定义形参数。 - 变长数组,可以用来改变函数中数组的维度,如二维数组的第二维
int sum2d(int rows, int cols, int ar[rows][cols]); // ar是一个变长数组 (VLA)
注意:rows与cols的声明要在arr的前面 - 复合字面量:
(int []){50, 20, 90} // 内含3个元素的复合字面量
类型名代表首元素的地址。
因为复合字面量是匿名的,所以不能先创建然后再使用它,必须在创建的同时使用它。如下用法
int * pt1;
pt1 = (int [2]) {10, 20};
int sum(const int ar[], int n);
...
int total3;
total3 = sum((int []){4,4,4,5,5,5}, 6);
第11章 字符串和字符串函数
- 函数:gets()、gets_s()、fgets()、puts()、fputs()、strcat()、strncat()、 strcmp()、strncmp()、strcpy()、strncpy()、sprintf()、strchr()、atoi()
- 用双引号括起来的内容称为字符串字面量(string literal),也叫作字符串常量(string constant)。
- 使用字符数组初始化时,相当于创建一个空间,再赋值为字符串常量,而指向字符串的指针则存放的是字符串常量的首地址。
- 如果要改变字符串或为字符串输入预留空间,不要使用指向字符串字面量的指针,而应该用字符数组。
const char *p = "abcde"
尽量加const - scanf读取字符串时遇到空白字符就停止,需要整行读入的时候使用gets(遇到换行符才停止),最好不要使用gets,用fgets代替。
- scanf()和gets()类似,也存在一些潜在的缺点。如果输入行的内容过长, scanf()也会导致数据溢出。不过,在%s转换说明中使用字段宽度可防止溢出。
第12章 存储类别、链接和内存管理
- 使用static创建静态变量。静态的意思是该变量在内存中原地不动,并不是说它的值不变。
- 当把一个静态变量声明定义到一个函数内时,静态变量在程序载入内存时已执行完毕,定义在函数内的目的是为了告诉编译器只有该函数能看到该静态变量。同理,在函数的形式参数中不能声明静态变量。
- 文件中使用其他文件的全局变量,需要用extern声明。如果一个变量想被该文件私有,则用static声明。
第13章 文件输入\输出
暂跳过
第14章 结构和其他数据形式
- 结构体变量的变量名和数组名不同,结构名只是其地址的别名。
- 联合(union)数据类型和枚举(enum)数据类型。
- 因为"[]“的优先级比”*“高,”()“的优先级与”[]"的优先级相同(从左到右),因此
int * risks[10];
// 声明一个内含10个元素的数组,每个元素都是一 个指向int的指针
int (* rusks)[10];
// 声明一个指向数组的指针,该数组内含10个int类 型的值 void (*pf)(char *);
// pf 是一个指向函数的指针。- 作为函数的参数是数据指针最常见的用法之一,函数指针亦如此。
第15章 位操作
- 按位运算符的优先级比==低。
- 有两种访问位的方法。一种方法是通过按位运算符,另一种方法是在结构中创建位字段。
第16章 C预处理器和C库
- 避免用++x 作为宏参数。
- 使用
#define
结合##
可以在编译时候自动生成a1,a2,a3,a4类似变量名。 - 定义内联函数最简单的方法是使用函数说明符 inline 和存储类别说明符 static。(在C中不加static则具有外部链接)。
- 由于并未给内联函数预留单独的代码块,所以无法获得内联函数的地址(实际上可以获得地址,不过这样做之后,编译器会生成一个非内联函数)。另外,内联函数无法在调试器中显示。
第17章 高级数据表示
#ADP以及一些数据结构略