C陷阱与缺陷

一章:词法陷阱(词法分析器)
1.代码间的空白(空格、制表、换行)将被忽略
2.= 与 ==
3.& && | || 的不同:位运算 与 逻辑运算
4.词法分析中的贪心法:每一个符号应该包含尽可能多的字符,来组成一个有意义的表达式或者操作符。 a---b ==> a-- - b
5.注意:不要无意中吧整形常量写成了 8进制 的格式了,46 != 046 != 0x46
6.字符与字符串:'/' "/";  
 ''代表一个字符
 ""代表一个无名数组起始的字符指针
如下的写法是错误的: char * p = '/'; '/'不是一个字符指针,"/"才匹配*p的要求


二章:语法陷进
1.(*(void(*)())0)(); ==> (*(函数指针)0)() ===> (*指针)():把0强制转换为一个函数指针,然后解引用获取到函数起始地址 ==> 函数调用()
2.void (*signal(int, void(*)(int)))(int); ==> void (*signal(int,函数指针))(int) ==> signal(int,函数指针)是一个函数地址,*函数地址:就是解引用的可用指针 void *指针 (int)
  ==> signal的返回值是一个 void (*)(int)的函数指针。     ----------》signal(int, void(*)(int))可以看作是一个函数指针 void *指针 (int),有事一个函数。
3.运算符优先级问题:解决办法,不确定时加上()进行优先级人工化
4.分号要注意加:否则 struct lo{ int a; int b} main(){} 导致这样编译器认为是main返回struct类型。哈哈哈
5.switch 小心中间的break,可以加可以不加,不加则继续往下执行咯。
6.int f();   f;这句话是计算f的地址,如上面 signal一样,signal代表他的地址,*signal代表解引用,
7.悬挂 else ;也就是匹配if不明确清晰


三章:语义陷进
1.一个数组对我们只能够做两件事情:1.确定该数组的大小:sizeof() 2.获取该数组的0元素指针
2.注意 int *p; int a[10]; 我们指针赋值可以: p = a; 但是绝对不能够 p =  &a;
 p是一个指向int内存地址的指针,a则是第一个元素的指针; *(a+2) 这样也是可以解开的。只要不越界访问即可。
 但是&a表示的是一个int[]数组的指针,不能赋值给一个int*。int (*p)[] = &a;这样还差不多;  //但是以前大多数c版本并没有这个概念,有些&a 与 a的值是一样的。所以还是要具体解释具体处理吧
3.可以这样赋值:int (*a)[32]; int b[12][32]; a = b;
4.for(b1; b2; b3){} 注意:b1表达式只执行一次哦,b2 b3就随着for次数执行多次,不满足b2就跳出哦。
5.作为参数的数组实则为一个指针来解释,并不知道其数组大小。
6.要防止浅拷贝哦
7.空指针不等于空字符串
8.int i, a[10];那么有很大的可能a[10]的地址就是i变量所处的地址。内存地址如是分配的,木有办法阿。我们要仔细知道上下边界,以免越界。
9.前缀++ -- 比后缀要快一点点,尤其是复杂类型的++--而言,因为中间需要存放临时变量
1.memcpy( char*dest, char *source, int k)
{
while( --k >= 0) *dest++ = *source++;
}
1.&& || 只要一边的表达式不满足,那么另一侧的表达式就不会去计算了:注意哦。
2.防止溢出哦。。。。。。
3.如果一个返回值为整形函数返回失败,那么实际上隐含地返回某个垃圾值。应该return 0; or  exit(0);


第四章:链接
1.连接器的输入是一组目标模块和库文件。连接器的输出是一个载入模块。处理各个目标模块中每个外部对象的命名冲突。
2.函数外部定义的对象,应该只定义一次,其他地方用到就使用extern引用(即外部对象)
3.外部对象前有static修饰,那么就说明仅仅在该源文件中有效,限制了作用域;对于其他源文件,a是不可见的。函数也同样适用。
4.虽然char int有时候是一样的,但是最好不好混用,因为他们指针是不一样大小的,一个1字节,一个4字节。
5.头文件:每个外部对象的声明都写在一个头文件里头,所有需要使用这些外部对象的地方,都包含这个头文件。
6.注意,C语言中,如果没声明函数,就使用了该函数,那么c会把这个函数当作 int为该函数的默认返回值。
7.不能定义了一个数组 char filename[]="123"; 而在其他地方却使用extern char* filename;这是不允许的。 同理:long i; extern int i;虽然兼容的类型,但是会有出错的几率很大。必须引用相同
8.在函数定义和声明之前调用,那么该函数被编译器默认为int返回类型咯。
9.多个源文件中可以定义同一个外部变量名,但是前提条件是要求他们定义为static修饰一下。
注意咯:程序编译时候的警告有可能成为以后的打问题,需要改的。一定要改掉警告哦。


第五章:库函数
1.fseek(fp, 0L, 1);我们通常使用fseek(fp,0,1);其实他要求的是Long实参,所以0L是最符合的
2.应该先检查返回值错误,才检查errno错误
3.信号编程是非常复杂棘手,而且具有一些本质上而言不可移植的特性。所以,signal处理函数我们尽可能的简单些,并将他们组织集中在一处,以便移植到新系统时进行修改和调试。


第六章:预处理器
1.好处:一处改变多出改变 2.可移植性:#define进行分别编译 3.避免小函数的调用开销,这些动作都定义成宏以减少调用开销
2.不能忽略宏定义中的空格。 宏就是文本替换而已,不会做其他任何操作的。
3.宏不是函数、不是语句、不是类型定义
4.#define T int*
  typedef int* T2
 T a,b; ==> int* a, b;
 T2 a,b;==> int *a,*b;这样就可以看出来宏不是类型定义,仅仅只是文本替换罢了


第七章:可移植性缺陷
1.typedef long mylong; 可移植性最好的办法就是声明该变量为long型。但新定义一个类型无疑更为清晰。
2.有符号字符和无符号字符在转换为int时具有陷阱;使用unsigned char会更加具有可移植性
3.除非运算 相比 位移运算来说,大大减慢了运行时速度。
4.int *p=NULL; 地址为0,但是系统不允许我们读取地位为0的内存,所以只要存在读取0地址的程序都会执行失败。
5.努力提高软件的可移植性实际上是延长了软件的生命期,大多数软件的生命期却要长于它运行其上的硬件。


第八章:建议与答案
我的缺点:还是比较急躁,不愿意去做习题。改阿改阿改阿。。




作者对c++程序员的3个最重要的建议:
1.避免使用指针
2.提倡使用程序库
3.使用类来表示概念









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值