第一章:快速开始
1.C语言中注释代码用/* 和*/来注释代码。但是由于/*和*/不能嵌套,故在需要对一大段代码注释的时候,内容代码不能含有注释/*,*/。但是可以采用宏命令来完成此功能。
#if 0
/*需要注释的大段代码 */
#endif
2.EOF是一个整数值,故在一个一个接受字符判断是否结束时,用int变量来存放获得的字符。否则255对应的字符类型转换成int型后等于-1.
int ch;
while ((ch = getchar() )!=EOF && ch!='\n')
第二章:基本概念
1.C语言从编译到执行的过程,合法标识符,转义序列,特别注意三字符序列的存在。
第三章:数据
1.C语言中四种基本数据类型:整型,浮点型,指针和聚合类型(struct,array).
2.使用typedef而不是#define来给类型命名别名。如下面列子:
#define ptr_to_char char *
ptr_to_char a, b; // b is char
typedef char * ptr_char;
ptr_char a,b; // both a and b are pointers
3.尽量用const修饰变量:不仅程序逻辑清晰,而且代码中尝试修改变量都会报错。
4.static用于定义函数或全局变量时,会将对应的链接属性从external改为internal,存储类型和作用域不变。对应函数和变量只能在声明他们的源文件中访问; static作用于代码内部变量声明时,会讲变量从局部变量改为静态变量。但是变量的链接属性和作用域不受影响。
第四章:语句
1.C语言中没有bool类型变量(见第三章第1条),用整型变量来代替(0代表false,1代表true)
2.C语言没有内置输入输出功能,I/O通过标准库函数进行实现。
3.goto唯一可以适合使用的场景是跳出多重循环。
第五章:操作符和表达式
1.注意逻辑移位与算术移位的区别.算术右移位时考虑数的正负号。
2.用移位操作对某个数的某一位操作:
value = value | 1<<bit_num; //置1
value = value & ~(1<<bit_num); //清零
value & 1<<bit_num; //测试是否为1
第六章:指针
1.对一个NULL指针进行解引用是非法操作。故在对指针进行解引用操作时,要确保指针不是NULL.
2.对指针进行算术运行的前提是两个指针是指向同一个array,否则结果是undefined.
3.指针指向一个array时,指针可以跟array最后一位的下一位进行比较。但若用指针与array第一位的前一位进行比较,标准未定义即undefined。故要避免此种用法。
3.指针要记得初始化,不用时记得设为NULL.(remember...)
第七章:函数
1.函数进行参数传递时,都是采用传值的方式。(原先参数的一份拷贝)。在传递array参数时,不是讲整个参数传递,而是传递了array的起始地址。
2.尾递归可以比较容易的用迭代实现。
第八章:数组
1.除了优先级外,间接引用可以和下标引用互换。
2. message大小为6.
char * message = "hello";
3.二维数组的传递:
int matrix[3][10];
func2(matrix);void func2(int (*mat)[10]);
void func2(int mat[][10]);
4.指针数组的理解:
int *ptr[10];
ptr是指向整型指针的指针,元素是指向整数的指针。
第九章:字符串,字符和字节
1.strlen的原型为:
size_t strlen(char const * string)
size_t是unsigned int 类型。故 if(strlen(x) >= strlen(y)) 与 if(strlen(x)-strlen(y) >=0) 不同,后者总是为true.
2.strncat函数一般会讲len个字符从src字符串加入到目标字符串,而且strncat总会在末尾加上一个NULL字符。
3.strncpy则总是复制n个字符,若原字符不足n个,则用NULL加到末尾。但是若n个字符最后一个不是NULL,则会出现最后的字符串是非NULL结尾的情形。故使用strncpy函数时,最好按如下方法:
strncpy(buffer, name, size);
buffer[size-1] = '\0';
4.为了提高程序的可移植性,减少对字符的直接操作。如判断一个字符是否是大写字符: if(ch >= 'A' && ch <= 'Z') 改为 if(isupper(ch))
5.对内存操作的几个函数:
// 若内存重叠,则结果undefined
void * memcpy(void *dst. void const * src, size_t length);
//与上一个函数类似,可以内存重叠
void *memmove(void *dst, void const *src, size_t lenth);
void *memcmp(void const *a, void const *b, size_t length);
void *memchr(void const *a, int ch, size_t length);
void *memset(void *a, int ch , size_t length);
第十章:结构和联合
1.Union 与Struct结构类似,只是Unino的所有成员引用的是内存中的相同地址。如果联合的各个成员具有不同的长度,联合的长度就是它最长成员的长度。
2.sizeof(struct X)包括任何由于端对其而浪费的内存。
3.free(NULL) is ok.
第十一章:动态内存分配
1.动态内存的分配与释放:
void *malloc(size_t size);
void free( void *pointer);
2.还有另外两个内存分配函数realloc和calloc:
void *calloc(size_t num_elements, size_t element_size);
void realloc(void *ptr, size_t new_size);
若ptr为NULL,则与malloc一样
第十二章:使用结构和指针
1.在对单链表进行操作时,主要对头结点和尾节点的考虑。
第十三章:高级指针话题
1.函数指针最常见的两个用途是转换表和作为参数传递给另一个函数
2.对函数指针执行间接访问之前必须把它初始化为指向一个函数:
int (*pf)(int) = &f;
int ans;
ans = f(25);
ans = (*pf)(25);
ans = pf(25);
第十四章:
1.几个基本预处理符号:
(1)__FILE__ // 进行编译的源文件名;
(2)__LINE__ // 文件当前行的行号;
(3)__DATE__ // 文件被编译的日期;
(4)__TIME__ // 文件被编译的时间;
(5)__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义;
2.#define宏使用时存在很多潜在的危险,如:
#define max(x,y) ( (x>y) ? (x) : (y) )
第十五章:
1.I/O函数以三种基本的形式处理数据:单个字符、文本行和二进制数据。
2.参考相应的手册。
第十六章:标准库函数
1.该部分比较复杂,书上也只是提及了部分的函数。如时间相关函数time,clock.随机数srand(),rand()。
2.fgets会在字符后加一个NULL.
char *fgets(char *buffer, int buffer_size, FILE * stream);
3.fputs可以输出一行或者一行的一部分。
3.gets未指定buffer的大小,故接收一行的多字符时会溢出。
char *gets(char *buffer)