一、词法陷阱
词法就是多个字符组合,构成一个词,这里采用贪心法。
1、注意|与||,&与&&,=与==之间的差异
2、注意整型常量,以0开始的是八进制
3、‘’与“”,前者是把字符转换成整型,后者是一个字符串常量的首地址。
例如可以:a = 1 + '0'; b = "123456“[1];
二、语法陷阱
语法就是多个词构成一条语句。
1.声明语句就是一个类型跟着一个表达式,这个表达式的求值是该类型。
例如void (*p)() ;p是一个函数,也可以这样生命(void (*)()) p.两者等价。把变量名字去除,整个表达式用括号包起来就是一个衍生出来的类型。
2.优先级 选择符 ->单目运算符->算术运算符->移位运算符->比较运算符->逻辑运算符->条件运算符->赋值->逗号
3.注意分号,switch中break,else悬挂问题。else只与同一个括号中最近的没有匹配的if结合
*注意:i[a]和a[i] 是*(a+i)的简写;p()是(*p)()的简写,即函数调用。
三、语义陷阱
1.虽然指针和数组在很多时候可以同样方式操作,但是并不是一样东西。存在不同:例如sizeof(),但是大多情况下,数组被转化成首地址操作。
2.C语言中只有一维数组,但是元素类型可以是任意类型,比如数组
3.指针之间的减法只能是属于同一个数组的两个指针之间的减法
4.字符串最后一般习惯使用'\0'当做结尾
5.数组类型的参数会自动转成指针
6.指针和指针指向的内容要分清楚
7.不对称边界,”谨慎边界,仔细推广“
8.求值顺序,只有四个运算确定(”||”,“&&”,“:?”,“,”)
9.逻辑运算结果是1或者0
10.有符号的整型运算才会溢出
11.main return 0表示成功
四、连接器
五、宏
使用宏的原因:1.减少开销2.统一修改一些符号
1.注意宏中的空格
2.变量和整个宏定义都要使用括号括起来,小心参数的副作用,例如i++
3.小心if-else悬挂
4.不是类型的定义,例如#define int * T_INT 之后声明,T_INT a,b;这里a就是整型指针,b就是整型
5.((void)(expression || printf("error"))) 这里选择逻辑运算实现,而不是if-else,是很有好处的。
六、移植性
就是说一些特性在不同的编译器上实现不同。
1.整型的长度
2.字符类型是否有符号
3.移位运算 是不是直接补0,不等价除2
4.除法的截断,只要求在被除数和除数为正时,余数为正
5.random函数返回值范围
6.toupper tolower
7.free释放会滞后一定时间,即free之后,还可以对该内存进行操作
8.最大负数和正数不匹配,即-n操作可能不是想要的结果