由 王宇 原创并发布 :
第1章词法陷阱
1.1=不同于==
1.2&和|不同于&&和||
1.3词法分析中的“贪心法”
规则:每一个符号应该包含尽可能多的字符。也就是说,编译器将程序分解成符号的方法是,从左到右一个字符一个字符地读入,如果该字符可能组成一个符号,那么在读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,指导读入的字符组成的字符串已不再可能组成一个有意义的符号。这个处理策略有时被称为“贪心法”或者,更口语化一点,称为“大嘴发”
a+++++b的含义(a++)+(++b)不是((a++)++)+b原因:a++不能为左值
1.4整数变量
141(十进制)0215(八进制)0x12(16进制);01951*8^2+9*8^1+5*8^0
1.5字符与字符串
C语言中的单引号和双引号含义迥异
第2章语法陷阱
2.1理解函数声明
如何C变量的声明都由两部分组成:类型以及一组类似表达式的声明符
一旦我们知道了如何声明一个给定类型的变量,那么该类型的类型转换符就很容易得到了:只需要把声明中的变量名和声明末尾的分号去掉,再将剩余的部分用一个括号整个“封装”起来即可
2.2运算符的优先级问题
表2-1
前述运算符(()[]->.)、单目运算符、双目运算符
双目运算符:算术运算符、移位运算符、关系运算符、逻辑运算符、赋值运算符、条件运算符
2.3注意作为语句结束标志的分号 :一个声明的结束需要有一个分号,struct{};
2.4switch语句
break特性
2.5函数调用 :f();
2.6"悬挂"else引发的问题
第3章语义陷阱
3.1指针与数组
C语言中数组需要注意两点:
1.C语言中只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来,然而C语言中数组的元素可以是任何类型的对象
2.对于一个数组,我们只能够做两件事:确定该数组的大小,以及获得指向该数组下标为0的元素的指针
int*p;inta[10];p=a;这个*p为a[0],错误:p=&a;
3.2非数组的指针
char*r,*malloc();r=malloc(strlen(s)+strlen(t));错误原因:
1.malloc函数有可能无法提供请求的内存.if(!r){}
2.给r分配的内存在使用完之后应该及时释放,这点务必要记住。free(r);
3.最重要的,就是调用malloc()函数时,并未分配足够的内存。malloc(strlen(s)+strlen(t)+1);
3.3作为参数的数组声明
我们没有办法可以将一个数组作为函数参数直接传递,被转换为指向该数组第1个元素的指针。
charhello[]="hello";printf("%s\n",hello);等效print("%s\n",&hell[0]);
intstrlen(ints[]){}等效intstrlen(int*s){}
main(intargc,int*argv[]){}等效main(intagrc,int**argv){}
3.4避免“举偶法”:混淆指针与指针所指向的数据
3.5空指针并非空字符串
编译器保证由0转换而来的指针不等于任何有效的指针
当常数0被转换为指针使用时,这个指针绝对不能被解除引用。换句话说,当我们将0赋值给一个指针变量时,绝对不能企图使用该指针所指向的内存中存储的内容
3.6边界计算与不对称边界 (待续)
C语言中一个拥有n个元素的数组,却不存在下标为n的元素,它的元素的小标范围是从0到n-1为此
栅栏错误的两个通用原则:
1.首先考虑最简单情况下的特例,然后将得到的结果外推,这是原则一
2.仔细计算边界,绝不掉以轻心,这是原则二
边界编程技巧:用第一个入界点和第一个出界点来表示一个数值范围。x>=16x<38;--n>=0
3.7求值顺序
即求值的副作用,C语言中只有四个运算符存在规定的求值顺序:&&||?:,
3.8运算符&&、||和!
同按位运算符&|~互换后可以正常工作,实际上是巧合
3.9整数溢出
C语言中存在两类整数算术运算,有符号运算与无符号运算
无符号算术运算中,没有“溢出”一说;一个运算符是有符号,另一个是无符号,有符号的会自动转换成无符号
当两个操作数都是有符号整数时,“溢出”就有可能发生,而且“溢出”的结果未定义。
3.10为函数main提供返回值
return0;
第4章连接
4.1什么是连接器
C语言中的一个重要思想就是分别编译,即若干个源程序可以在不同的时候单独进行编译,然后在恰当的时候整合到一起,但是连接器一般是与C编译器分离的,它不可能了解C语言的诸多细节
4.2声明与定义
inta;位置出现在所有的函数体之外,被称为外部对象a的定义;声明并初始化,默认为0;
externinta;a是一个外部整形变量,从连接器的角度来看,声明是一个对外部变量a的引用,而不是对a的定义
4.3命名冲突与static修饰符
static修饰符是一个能够减少命名冲突的有用工具
4.4形参、实参与返回值
4.5检查外部类型
保证一个特定名称的所有外部定义在每个目标模块中都有相同的类型,一般来说是程序员的责任
4.6头文件
规则:每个外部对象只在一个地方声明。这个声明的地方一般就在一个头文件中,需要用到该外部对象的所有模块都应该包括这个头文件。特别需要指出的是,定义该外部对象的模块也应该包括这个头文件
第5章库函数
5.1返回整数的getchar函数
5.2更新顺序文件
fopen一个文件后,不可以自由地交错进行读出和写入的操作。如果要同时进行输入和输出操作,必须在其中插入fseek函数的调用
5.3缓冲输出与内存分配
setbuf(stdout,buf);通知输入输出库,所有写入到stdout的输出都应该使用buf作为输出缓冲区,知道buf缓冲区被填满或程序员直接调用fflush,buf缓冲中的内容才实际写入到stdout中
注意setbufmain
5.4使用errno检测错误
5.5库函数signal
第6章预处理器
宏作用:使多个不同变量的类型可在一个地方说明:
#defineFOOTYPEstructfoo
FOOTYPEa;
大多数C语言实现在函数调用时都会带来重大的系统开销。因此我们也许希望有一种程序块,它看上去像一个函数,但却没有函数调用的开销
6.1不能忽视宏定义中的空格
#definef空格(x)((x)-1)f宏无参数,f代表(x)((x)-1)
6.2宏并不是函数
定义最大数值宏
#definemax(a,b)((a)>(b)?(a):(b))缺陷如下:
max(i,i++)展开则:((i)>(i++)?(i):(i++))副作用
修正:
staticinta_temp,b_temp;
#definemax(a,b)(a_temp=(a),b_temp=(b),a_temp>b_temp?a_temp:b_temp)
6.3宏并不是语句
#defineassert(e)if(!e)assert_error(__FILE__,__LINE__) if(x>0&&y>0) assert(x>y); else assert(y<x);
展开错误
if(x>0&&y>0) if(x>y)assert_error("foo.c",37); else if(y<x)assert_error("foo.c",38);
6.4宏并不是类型定义
#defineT1structfoo*
typedefstructfoo*T2
第7章可移植性缺陷
7.1应对C语言标准变更
7.2标识符名称的限制
ANSIC标准所能保证的只是,C实现必须能够区别处前6个字符不同的外部名称。而且,这个定义中并没有区分大写字母与其对应的小写字母
intFun(int) { intp=10; p=fun(p); }
合法的递归
7.3整数的大小
8位char1字节
32位intlongfloat4字节
16位short2字节
64位double8字节
7.4字符是有符号整数还是无符号整数
8位的取值范围:
有符号:-128~127高1位为1是负数,0是整数
无符号:0~255
二进制的表示方法,同正负符号的存储不同,二进制是补码,正负符号的存储同上
反码:所有位求反
补码:反码加1
常见错误认识是:如果c是一个字符变量,使用(unsigned)c就可得到与c等价的无符号整数。这是会失败的,因为在将字符c转换为无符号整数时,c将首先被转换为int型整数,而此时可能得到非预期的结果
正确的方式:(unsignedchar)c
7.5移位运算符
如果被移位的对象是无符号的数,那么空出的位将被0填充
如果被移位的对象是有符号的数,那么既可以用0填充空出的位,也可以用符号位的副本填充空出的位
移位计数必须大于或等于0,而严格小于n(n长度,例如intn=32)
7.6内存位置0
在所有的C程序中,误用null指针的效果都是未定义的
7.7除法运算时发生的截断
7.8随机数的大小
ANSIC标准,定义的随机数的最大值:RAND_MAX
7.9大小写转换
#definetoupper(c)((c)+'A'-'a')
#definetolower(c)((c)+'a'-'A')
依赖于特定实现中字符集的性质,既需要所有的大写字母与相应的小写字母之间的差值是一个常量,ASCII字符集符合
7.10首先释放,然后重新分配
malloc()free()realloc()
7.11可移植性问题的一个例子
第8章建议与答案
相关推荐
C语言作为一门历史悠久且应用广泛的编程语言,在实际开发过程中,存在着不少容易让人忽视的缺陷和陷阱。本文将对这些缺陷和陷阱进行详细的分析,并提供相应的解决方案。 #### 二、具体缺陷与陷阱 ##### 1. 表达式...
S7-200 Smart入门笔记4——全局变量和局部变量 S7-200 Smart入门笔记5——子程序 S7-200 Smart入门笔记6——中断1 S7-200 Smart入门笔记7——中断2 S7-200 Smart入门笔记8——电机控制子程序调用1-OUT S7-200 Smart...
云的学习笔记-云的学习笔记系统-云的学习笔记系统源码-云的学习笔记管理系统-云的学习笔记管理系统java代码-云的学习笔记系统设计与实现-基于ssm的云的学习笔记系统-基于Web的云的学习笔记系统设计与实现-云的学习...
云的学习笔记-云的学习笔记系统-云的学习笔记系统源码-云的学习笔记管理系统-云的学习笔记管理系统java代码-云的学习笔记系统设计与实现-基于ssm的云的学习笔记系统-基于Web的云的学习笔记系统设计与实现-云的学习...
从给定的内容中,虽然信息显得杂乱无章,但我们仍可以提取出关于...对于学习C语言的同学们,通过阅读这类“C语言缺陷与陷阱”的资料笔记,能够更好地理解C语言的特性,并学会如何安全、高效地使用这种强大的编程语言。
《C语言缺陷与陷阱》笔记概述 C语言作为一种强大的编程工具,因其低级特性而备受程序员喜爱,但也因其潜在的缺陷和陷阱而让初学者困惑。这篇笔记详细探讨了C语言在不同层面可能存在的问题,旨在帮助开发者更好地...
《谭浩强C语言程序设计--简明笔记》是一份针对C语言学习者的详细学习资料,涵盖了C语言的基础知识、程序结构、数据类型、运算符和表达式等关键概念。以下是从这份资料中提炼出的重要知识点: ### C语言标准与历史 ...
TypeScript Quickly-2020-英文版 学习笔记 TypeScript Quickly-2020-英文版 学习笔记 TypeScript Quickly-2020-英文版 学习笔记 TypeScript Quickly-2020-英文版 学习笔记 TypeScript Quickly-2020-英文版 学习笔记 ...
在C语言的学习中,翁恺教授的慕课是许多初学者和进阶者的重要资源。以下是一些基于标题和描述中的关键知识点的详细说明: 1. **运算符和运算优先级**(第二周-运算优先级):C语言中有多种运算符,包括算术运算符...
【标题】"头歌C语言实验答案el-for-network-ids-ma笔记"涉及到的主要知识点是C语言编程和网络入侵检测系统(Network Intrusion Detection System, NIDS)的基础知识,特别是利用深度学习技术如卷积神经网络(CNN)、...
Software Engineering at Google-2020-英文版 学习笔记 Software Engineering at Google-2020-英文版 学习笔记 Software Engineering at Google-2020-英文版 学习笔记 Software Engineering at Google-2020-英文版 ...
spp-net论文阅读笔记
DA-TransUNet论文阅读笔记