c语言深度剖析读书笔记

上传人:第*** 文档编号:34519423 上传时间:2018-02-25 格式:DOCX 页数:17 大小:28.61KB
返回 下载 相关 举报
c语言深度剖析读书笔记_第1页
第1页 / 共17页
c语言深度剖析读书笔记_第2页
第2页 / 共17页
c语言深度剖析读书笔记_第3页
第3页 / 共17页
c语言深度剖析读书笔记_第4页
第4页 / 共17页
c语言深度剖析读书笔记_第5页
第5页 / 共17页
点击查看更多>>
资源描述

《c语言深度剖析读书笔记》由会员分享,可在线阅读,更多相关《c语言深度剖析读书笔记(17页珍藏版)》请在金锄头文库上搜索。

1、C 语言深度剖析读书笔记第 1 章关键字1.1、定义与声明的区别:定义创建了对象并为对象分配了内存,声明没有分配内存1.2、register 请求编译器尽可能将变量存在 CPU 寄存器中以提高访问速度,register 变量必须为 CPU 寄存器所能接受的类型,它须是一个单一的值,并且长度struct st1char a ;int b ;short c ;struct st2char a; struct st1 b; /复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式int c;int main(int argc, char *argv)printf(%d %dn, sizeof(st

2、ruct st1), sizeof(struct st2);return 0;运行结果:12 20St1 :char 占一个字节,起始偏移为 0 ,int 占 4 个字节,min(#pragma pack()指定的数,这个数据成员的自身长度) = 4(VC6 默认 8 字节对齐),所以 int 按 4 字节对齐,起始偏移必须为 4 的倍数,所以起始偏移为 4,在 char 后编译器会添加 3 个字节的额外字节,不存放任意数据。short 占 2 个字节,按 2 字节对齐,起始偏移为 8,正好是 2 的倍数,无须添加额外字节。到此规则 1 的数据成员对齐结束,此时的内存状态为:oxxx| ooo

3、o| oo0123 4567 89 (地址)(x 表示额外添加的字节)共占 10 个字节。还要继续进行结构本身的对齐,对齐将按照#pragma pack 指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行,st1 结构中最大数据成员长度为int,占 4 字节,而默认的#pragma pack 指定的值为 8,所以结果本身按照 4 字节对齐,结构总大小必须为 4 的倍数,这样在处理数组时可以保证每一项都边界对齐,需添加 2 个额外字节使结构的总大小为 12 。此时的内存状态为:oxxx|oooo|ooxx0123 4567 89ab (地址)到此内存对齐结束。St1 占用了 12 个

4、字节而非 7 个字节。3.7、宏参数中的#字符串中包含宏参数,那我们就可以使用“#”#define SQR(x) printf(The square of #x is %d.n, (x)*(x);再使用:SQR(8);则输出的是:The square of 8 is 64.3.8、#这个运算符把两个语言符号组合成单个语言符号。看例子:#define XNAME(n) x # n如果这样使用宏:XNAME(8)则会被展开成这样:x8#将前后两部分粘合起来第 4 章、指针和数组4.2、int a5. sizeof(a5)关键字 sizeof 求值是在编译的时候。虽然并不存在 a5这个元素,但是这里

5、也并没有去真正访问 a5,而是仅仅根据数组元素的类型来确定其值。所以这里使用 a5并不会出错。4.3.3 指针和数组的定义与声明。要确认你的代码在一个地方定义为指针,在别的地方也只能声明为指针;在一个的地方定义为数组,在别的地方也只能声明为数组。如文件 1 中定义 char a100 = 0x31, 0x32, 0x33, 0x34, 0x35;文件 2 中这样进行声明 extern char *a;虽然在文件 1 中,编译器知道 a 是一个数组,但是在文件 2 中,编译器并不知道这点。大多数编译器是按文件分别编译的,编译器只按照本文件中声明的类型来处理。所以,虽然 a 实际大小为 100 个

6、 byte,但是在文件 2 中,编译器认为 a 是一个 char*指针,只占 4 个 byte。编译器会把存在指针变量中的任何数据当作地址来处理。故文件 2 中 a 存放的数据其实是文件 1 中数组 a 的前 4 个元素,即文件 2 中 a=0x34333231(小端机器),对这个未定义的地址进行访问,所以出错了。C 语言多文件编译时,编译器不检测其声明的变量类型与定义时的类型是否匹配4.5 指针的算术运算/* Compiler: GCC* Last Update: Sat 21 Apr 2012 05:25:43 PM CST*/#include int main(int argc, cha

7、r *argv)char a7=A,B,C,D, E, F;char (*p3)3 = /编译会提示 warning,运行没错,最好别这样用char (*p4)3 = a; /编译会提示 warning,运行没错,最好别这样用int b2;printf(%dn, /相减也是以步长来计算printf(%sn, *p3);/指针相加就是加上指针的步长,这里是+ sizeof(char 3)printf(%sn, *(p3 + 1);printf(%cn, *p3); printf(%sn, *p4);printf(%sn, *(p4 + 1); /+ sizeof(char 3)printf(%c

8、n, *p4);return 0;运行结果:1ABCDEFDEFAABCDEFDEFA4.6.3 二维数组参数与二维指针参数,二维数组初始化void fun(char a34);可以把 a34理解为一个一维数组 a3,其每个元素都是一个含有 4 个 char 类型数据的数组。上面的规则, 语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针。也就是说我们可以把这个函数声明改写为:void fun(char (*p)4);/* Compiler: GCC* Last Update: Sat 21 Apr 2012 05:36:16 PM CST*/#includ

9、e int main(int argc, char *argv)int a4=0,0,3,0,10; /第一个表示对第一行元素进行赋值,第二个对第二行.int i, j;for(i = 0; i int f(int a)return a;int main(int argc, char *argv)int (*ptrF1)(int) = f; int (*ptrF2)(int) = printf(%x %xn, f, f + 1); /函数指针+1 的结果就是该指针值直接加 1,不需考虑步长printf(%x %xn, return 0;运行结果:80483c4 80483c580483c4 8

10、0483c5函数名是在编译时关联到某个地址.直接使用函数名的时候是指那个地址在函数名前加&还是那个地址,要具体了解原理得从编译器的角度出发下面是我用 gdb 调试的结果,&f、f、*f、*f 的值都是一样的Breakpoint 1, main (argc=1, argv=0xbffff374) at 1.c:1515 int (*ptrF2)(int) = (gdb) p f$1 = int (int) 0x80483c4 (gdb) p &f$2 = (int (*)(int) 0x80483c4 (gdb) p *f$3 = int (int) 0x80483c4 (gdb) p *f$4

11、 = int (int) 0x80483c4 4.7.3 C Traps and Pitfalls书中的一个例子: (* ( void (*) ( ) )0 )( )第一步:void(*) (),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。第二步:(void(*) ()0,这是将 0 强制转换为函数指针类型,0 是一个地址,也就是说一个函数存在首地址为 0 的一段区域内。第三步:(*(void(*) ()0),这是取 0 地址开始的一段内存里面的内容,其内容就是保存在首地址为 0 的一段区域内的函数。第四步:(*(void(*) ()0)(),这是函数调用。第 5 章、内存管理

12、5.1、野指针,也就是指向不可用内存区域的指针。通常对这种指针进行操作的话,将会使程序发生不可预知的错误。“野指针”不是 NULL 指针,是指向“垃圾”内存的指针。人们一般不会错用 NULL 指针,因为用 if 语句很容易判断。但是“野指针”是很危险的,if 语句对它不起作用。野指针的成因主要有两种:一、指针变量没有被初始化。任何指针变量刚被创建时不会自动成为 NULL 指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为 NULL,要么让它指向合法的内存。二、指针 p 被 free 或者 delete 之后,没有置为 NULL,让人误以为 p 是个

13、合法的指针。别看 free 和 delete 的名字恶狠狠的(尤其是 delete),它们只是把指针所指的内存给释放掉,但并没有把指针本身干掉。通常会用语句 if (p != NULL)进行防错处理。很遗憾,此时 if 语句起不到防错作用,因为即便 p 不是 NULL 指针,它也不指向合法的内存块5.2、定义数组 int a10,用 memset(a, 0, sizeof(a)对其进行初始化5.3、assert 是一个宏,而不是函数。如果其后面括号里的值为假,则程序终止运行,并提示出错;如果后面括号里的值为真,则继续运行后面的代码。这个宏只在 Debug 版本上起作用,而在 Release 版

14、本被编译器完全优化掉,这样就不会影响代码的性能。5.3.5.3、malloc()申请 0 字节内存man 3 mallocIf size is 0, then malloc() returns either NULL,or a unique pointer value that can later be successfully passed to free().示例:/* Compiler: GCC* Last Update: Sat 21 Apr 2012 11:59:22 PM CST*/#include #include #include int main(int argc, char *argv)char *c = malloc(0);if(c != NULL) /申请 0 字节,返回不是 NULLstrcpy(c, aaaaaaaaaaaaaaa);puts(c);free(c); /free 出错了return 0;5.3.5.4、v

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 解决方案

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号