《c陷阱与缺陷》笔记
——————2011/12
1. 表达式的结合:依次尽可能多的读取字符,直到读取下一个不能组成完整意义的字符(贪心法),或遇到空白(空格,tab,回车)停止。 (有的运算符从右到左结合)
2. 声明表达式的意义: 一个声明(如: float f,g;),对表达式f或g求值的结果为float型, 那么float ((a)); 对((a))求值也为float行,所以a为float型。 一旦知道了如何声明一个变量,那么该变量的类型转换符也很容易知道:去掉声明中的变量名和分号,在把剩余部分用括号括起来即可。(例如:void (*fp)(); 类型转换符为(void (*)() 。) 。调用地址为0处的该类型的函数:(*(void (*)())0)(); ),引入typedef后方便多了。
3. 运算符优先级 ::作用域访问符高于一切
算数,移位,关系,位,逻辑,条件,赋值(从右至左),逗号。
4. 数组与指针
int a[4]; int *pa; 数组名a表示该数组元素首部的地址( pa = a,则pa存储的为数组a的首地址),但sizeof(a)的值却是整个数组的大小,并不为指针所占的内存大小。
a[i]等价于*(a+i),他们均表示数组a的第i个元素的引用。
int b[4][5]; int *pb; 数组b表示以4个int[5]数组为元素的一维数组(没有真正的二维数组),
b[3]表示数组b最后一个元素所指向的地址,即最后一个int型数组元素的起始地址,(pb = b[3],则pb指向最后一个int型数组的首地址) b表示以一维数组为元素的数组的首地址,指向的是int[5]型的数组,而pb是指向int型,所以pb=b会产生编译错误,因为类型不匹配。 那么定义一个指向int[5]型数组的指针则可以赋值,即int (*p) [5]; p=b则正确。
(语义陷阱3.1:当不清楚时回头看看声明变量时是怎么定义的!!!)
5. 外部变量与局部变量
分清楚声明与定义,类型一定要匹配。外部变量自动赋初值0,局部变量声明后,必须初始化才能使用(局部int a; printf(“%d”,a);将会出错,因为声明局部变量a之后未初始化,但是万能的指针能访问)。
6. 强制让输出不进行缓冲:setbuf(stdout, (char *) 0 );
调用库函数时一定要清楚的知道其返回类型,特别是用于判断语句时。
7. 宏中一个表达式的每一个变量一定要用括号括起来,整个表达式也要用括号括起来。
#define MAX(a,b) ((a)>(b)?(a):(b)) 倘若不加括号,那么调用2*MAX(3-2,2-1)+1;试试,宏定义时,还要注意第一个空格符不能随意出现。宏命名应该用大写(无论是函数还是变量)。
8. 在一个平台上写程序时,一定要注意各个基本类型占用的内存大小,选择适当的类型时,若考虑到移植性问题,则可用typedef来定义,这样如果一直到其他平台要更改这个类型时,只需改typedef一处即可。
9. c之I/O接口
《c和指针》笔记
——————2012/3
1. 用预处理来注释不要的代码。(方便)
#if 0
statements
#endif
2. struct{int a; char b; char c;};与struct{char a; int b; char c;};占用的内存大小不同,取决于系统机器的整型长度,若整型为4个字节 ,那第一个占用8字节,第二个占用12字节。
3. 指针函数主要用于回调函数和转移表。回调函数(在一个有num,name,pNext成员的学生链表中,查找一个给定的value,可用num,name两种查询,应定义两种比较函数和一个查询函数,将指向比较函数的指针作为参数传递给查询函数,采用函数回调方式);转移表(定义指向函数的指针数组,如:int (*f[])(parameters);每一个数组成员便是一个指向特定操作的函数的指针,这样可以避免庞大的switch操作)
函数名可以作为函数形参数,参数传递时,编译器自动将该函数名转换为指向函数的指针,就如同数组名做形参一样。而函数的返回类型则不能是函数名,他不会自动转换为指针,所以必须定义为指向函数的指针,就如同函数的返回类型不能是数组,要用指向数组的指针一样。
4. 字符串常量
"xyz"+1 表示字符y的地址。(因为常量"xyz"表示该字符常量的首地址。) &"abcdef"[2]表示字符c的地址
5. #if defined(File) #if !defined(File)
#ifdef File #ifndef File
每一对是等价的。但用#if可以嵌入其他表达式: #if a<0 && defined(MAXSIZE)
6. 可变参数函数列表<stdarg.h>
一般不要使用。(在面向对象编程时容易导致接口模糊)
7. c程序中加入汇编代码:
_asm
{
mov ax,10
}