《C陷阱与缺陷》阅读笔记(个人版)
笔记:
第一章:词法陷阱
提倡显示比较
if((x = y) != 0)
foo();
第二章:语法陷阱
已知一个类型的声明
该类型的类型转换:吧声明中的变量名和声明末尾的分号去掉,再将剩余的部分用括号整个“封装”起来即可
(*(void(*)())0);
(void(*)()) 这是一个返回值为void的函数指针类型
typedef void (*funcptr)() 中 funcptr 等价于 (void(*)())
typedef void (*funcptr)(); //funcptr表示返回值为void的函数指针,
可以引用同类型返回值的函数,有无参数都可以,
但是如果显式声明带有参数,如typedef void (*funcptr)(int);则只能引用带有一个int参数返回void的函数
当然没有参数的函数可以传递一个无效的参数进行引用
void test(){return;} funcptr cp = (funcptr)test; cp(0);
优先级问题:
单目 大 双目 (移位 小 算术 关系紧跟后) 逻辑 赋值 条件
终极必杀: 加括号
第三章:语义陷阱
C语言中只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来
二维数组就是以数组为元素的数组
int (*ap)[31] : *ap是一个拥有31个整型元素的数组,因此ap就是一个指向这样的数组的指针
空指针 p = NULL 地址是无效的 并不是空字符串 空字符串是地址是有效的 只不过内存中的内容为空
声明缓冲区
#define N 1024
static char buffer[N];
提到一点:--n 可能要比 n++ 快 理由:n++要先保存n在减1 (理由不是太懂,感觉写的不清楚)
运算符 && || 首先对左侧操作数求值,只在需要的时候才对右侧操作数求值 -> 让最可能对表达式起到作用的操作数在左边(提高速度)
对于数组结尾之后的下一个元素,取它的地址是合法的,但是取地址内的内容是不合法的
整数溢出
无符号算术运算是以2的n次方为模(n是结果中的位数),相当于时钟循环 11点加2个小时 是1点(实际上也溢出了)
两个操作数都是有符号整数时,“溢出”会出现
if((unsigned)a + (unsigned)b > INT_MAX):转换为无符号数来判断是否溢出
char a = 126;
char b = 125;
printf("十六进制:%x\n",a);
printf("十六进制:%x\n",b);
printf("十进制:%d\n",a);
printf("十进制:%d\n",b);
printf("%d\n", CHAR_MAX);
printf("-------------------\n");
printf("十六进制:%x\n", (unsigned char)a + (unsigned char)b);
printf("十进制:%d\n", (unsigned)a + (unsigned)b);
printf("差:%d\n", (unsigned)a + (unsigned)b - CHAR_MAX);
第四章:连接
若干个文件分别编译 连接器将若干个C源程序整合成一个整体
外部变量存在定义与声明 声明可以有多个 定义只能有一个 如果没有赋初始值 会自动初始化为0
前面加 static修饰 可以起到“屏蔽”的作用 使得被修饰的变量或函数 值在本源文件中可见
定义:char filename[] = "/etc/passed"; /*filename是一个字符数组的名称 类型是“字符数组”*/
另一文件中声明:extern char *filename; /*filename是一个字符指针 类型是指针*/
C语言的规则:如果一个未声明的标识符后跟一个开括号 那么它将被视为一个返回整型的函数
main(){} 有返回值并且是整型
第五章:库函数
getchar函数的返回值类型是 整数(int)为了可以接收getchar返回的全部 需要定义一个 int类型的变量来接收它的返回值
更新顺序文件
为了保持与过去不能同时进行读写操作的程序的向下兼容性,一个输入操作不能随后直接紧跟一个输出操作,反之亦然。
如果要同时进行输入和输出操作,必须在其中插入fseek函数的调用
缓冲区输出与内存分配:setbuf(stdout, buf) 的使用有风险 ---- 经典错误
errno signal 的使用复杂
第六章:预处理器
特别注意 宏定义中的空格 #define f (x) ((x) - 1) f -> (x) ((x) - 1)
宏不是函数 只是一种替换 要多加括号防止意外
带有多次计算的时候 要特别注意
宏不是语句 定义时候一般不需要加 分号
宏不是类型定义
#define INTP int *
INTP a, b; 替换后 int * a, b; 则a是int指针 b是int数据
typedef int *INTP;
INTP a, b; a b都是int指针
第七章:可移植性缺陷
函数声明中略去参数类型的说明,这在ANSI C 标准中也是合法的
因为这样的声明并没有对参数类型做出任何说明,就意味着如果在函数调用时传入了错误类型的参数,函数调用就会不声不响地失败
C语言实现必须能够区别出前6个字符不同的外部名称,而且,这个定义中并没有区分大小写字母
为了移植性可以定义自己的数据类型:typedef long my_long
(unsigned) c :c从char型转换为int型整数 再转换为无符号int 从8位到32位
(unsigned char) c :c从char转换为无符号char
char c = 'a';
printf("%d\n", sizeof((unsigned char) c)); //输出1
printf("%d\n", sizeof((unsigned) c)); //输出4
移位运算
左移 后面补0
右移 逻辑 :无符号 使用逻辑:左边补0 / 算术 :有符号 使用算术:左边补符号位的副本
一般非负 右移一位 <=> 除2 (整数运算)
先释放在重新分配 --- 按照自己现有的方案写
字符串常量可以用来表示一个字符数组
"0123456789"[2] => '2' //取数组的下标为2的字符
建议
不要舒服自己相信“皇帝的新装”
while(c == 't' || c = ' ' || c == '\n')
c = getc(f);
直接了当地表明意图
当你编写代码的本意是希望表达某个意思,但这些代码有可能被误解为另一种意思时,请用括号或者其他方式让你的意图尽可能清楚明了
while('\t' == c || ' ' == c || '\n' == c)
c = getc(f);
考察最简单的特例
着重注意输入数据为空或者只有一个元素
使用不对称边界
注意数组小标从0开始
注意潜伏在暗处的Bug
程序的生命期往往要长于它运行其上的机器的生命期(可移植性)
防御性编程
多考虑坏的情况并加以处理
附录A
精度修饰符:指定打印数字的最小位数,不足前面补0
printf("%.3d\n", 7); 007 //整数---一共的位数
printf("%03d\n", 7); 007
printf("%.3f\n", 7.2345); 7.235 //小数---小数点后的位数
修饰符 l(long) 只对用于整数的格式码有意义
但是printf("%lf\n", 3.14); 可以打印出 3.140000
可变参数...
本节完......
《C陷阱与缺陷》阅读笔记(个人版)的更多相关文章
- C陷阱和缺陷学习笔记
这段时间把<C陷阱和缺陷>看了,没时间自己写总结.就转一下别人的学习笔记吧http://bbs.chinaunix.net/thread-749888-1-1.html Chapter 1 ...
- C的陷阱和缺陷研读笔记01
词法分析: 编译器将程序分解成符号的方法是 从左到右一个一个字符的读入,如果该字符可能组成一个符号,再读入下一个字符 而c语言里的符号 / * =只有一个字符长, 是单字符的, /* == 一些事双字 ...
- C陷阱与缺陷学习笔记
导读 程序是由符号(token)序列所组成的,将程序分解成符号的过程,成为"词法分析". 符号构成更大的单元--语句和声明,语法细节最终决定了语义. 词法陷阱 符号(token)指 ...
- C的陷阱和缺陷研读笔记02
宏: 宏不是函数 展开会产生庞大的表达式 #define MIN(A,B) ((A) <= (B) ? (A) : (B))MIN(*p++, b)会产生宏的副作用 剖析: 这个面试题主要考查面 ...
- 《c陷阱与缺陷》笔记--注意边界值
如果要自己实现一个获取绝对值的函数,应该都没有问题,我这边也自己写了一个: void myabs(int i){ if(i>=0){ printf("%d\n",i); }e ...
- 《c陷阱与缺陷》笔记--移位运算
#include <stdio.h> int main(void){ int a = 2; a >> 32; a >> -1; a << 32; a & ...
- C陷阱与缺陷读书笔记
2.1理解函数声明 这一章仔细分析了(*(void(*)())0)();这条语句的含义,并且提到了typedef的一种函数指针类型定义的用法. 我们经常用到的typedef用法是用于指定结构体的类型, ...
- 读书笔记--C陷阱与缺陷(七)
第七章 1.null指针并不指向任何对象,所以只用于赋值和比较运算,其他使用目的都是非法的. 误用null指针的后果是未定义的,根据编译器各异. 有的编译器对内存位置0只读,有的可读写. 书中给出了一 ...
- 读书笔记--C陷阱与缺陷(一)
要参与C语言项目,于是作者只好重拾C语言(之前都是C++,还是C++方便). 看到大家都推荐看看 C陷阱与缺陷(C traps and pitfalls),于是好奇的开始了这本书的读书之旅. 决定将 ...
- 阅读《C陷阱与缺陷》的知识增量
版权声明:本文为Focustc原创文章.转载请注明作者及出处. https://blog.csdn.net/caozhankui/article/details/35925939 看完<C陷阱与 ...
随机推荐
- 【CF771A】Bear and Friendship Condition
题目大意:给定一张无向图,要求如果 A 与 B 之间有边,B 与 C 之间有边,那么 A 与 C 之间也需要有边.问这张图是否满足要求. 题解:根据以上性质,即:A 与 B 有关系,B 与 C 有关系 ...
- Python 基础数据类型之set
set是一个无序且不重复的元素集合,相当于字典的键,不重复,不可变 一.set变量初始化 A = set() #注意在创建空集合的时候只能使用s=set(),因为s={}创建的是空字典 B = {&q ...
- CCNA学习与实验指南——第3章 以太网
以太网就是局域网,IEEE制定了802.2和802.3两种标准.802.2规定了OSI模型的数据链路层的上半部分(LLC子层),802.3规定了OSI模型的数据链路层的下半部分和物理层(MAC子层). ...
- python---django初步了解以及安装(包括Django网页首次无法访问的原因及解决方法,以及在linux服务器上布置无法启动的原因)
pip install Django 相关网站资源: Python下有许多款不同的 Web 框架.Django是重量级选手中最有代表性的一位.许多成功的网站和APP都基于Django. Django是 ...
- SQL记录-PLSQL变量与常量文字
PL/SQL变量 变量是只不过是一个给定的存储区域,程序可以操纵的名称.PL/SQL每个变量具有一个特定的数据类型,它决定了大小和变量的存储器的值,可以说存储器和设置操作可以施加到可变内被存储的范 ...
- Java日期比较
在进行业务处理时,遇到一个需要比较日期但是不包含时分秒的判断问题 SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd"); ...
- 比马卡龙好看N倍的中式甜点
- day63_SpringMVC学习笔记_01
1.JAVAEE体系结构 JAVAEE体系结构图如下所示: 2.什么是springmvc? 什么是mvc? Model1 Model2 SpringMVC是什么? SpringMVC是一个web层mv ...
- HTML5 JavaScript实现图片文字识别与提取
8月底的时候,@阿里巴巴 推出了一款名为“拯救斯诺克”的闯关游戏,作为前端校园招聘的热身,做的相当不错,让我非常喜欢.后来又传出了一条消息,阿里推出了A-star(阿里星)计划,入职阿里的技术培训生, ...
- 【LibreOJ】#6354. 「CodePlus 2018 4 月赛」最短路 异或优化建图+Dijkstra
[题目]#6354. 「CodePlus 2018 4 月赛」最短路 [题意]给定n个点,m条带权有向边,任意两个点i和j还可以花费(i xor j)*C到达(C是给定的常数),求A到B的最短距离.\ ...