C专家编程
第一章
1,在函数定义中形参的数量最大是31个,函数调用时实参的数量最大也是31个,一条源代码行里至少可以有509个字符,在表达式中可支持32层嵌套的括号。
2,const float * 类型是指向一个具有const限定符的float类型的指针。
3,const int *limitp=&limitp;limitp是一个指向常量整型的指针,这个指针不能用于修改这个整型数,但是在任何时候,这个指针本身的值确可以改变,这样它就指向了不同的地址,,对它
解除引用操作时就会得到一个不同的值。
4,const和*组合通常只用于在数组形式的参数中模拟传值调用。它声称“我给你一个指向它的指针,但你不能修改它”。这个约定类似于void *用法。理论上可以用于任何情形,但通常会限制于把指针
从一个类型转换为另一种类型。
5,尽量不要使用无符号类型,因为负数会被翻译成无穷大。只有在使用位段和二进制代码时,才可以用无符号数。应该在表达式中使用强制类型转化,使操作数均为有符号或无符号,这样就不必由编译器
选择结果的类型。
6,一个L的NULL用于结束一个ASCII字符串,两个L的NULL用于空指针。
第二章
1,在c语言中一个符号要么全局可见,要么对其它文件都不可见。
2,c语言的重载:
static:在函数内部即局部变量+static,表示该变量值在各个调用间一直保持延续性;在函数一级即函数名前加static,表示该函数只对本文件可见。
extern:用于函数定义,表示全局可见(属于冗余的因为默认的就是全局可见),用于变量表示它在其它地方定义。
void:作为函数返回类型,表示不返回任何值;在指针声明中,表示通用指针的类型;位于参数列表中,表示没有参数。
*:乘法运算符;用于指针,间接引用;在声明中表示指针。
&:位的AND操作符;取地址操作符;
():在函数定义中,包围形式参数表;调用一个函数;改变表达式的运算次序;强制类型转化;定义带参数的宏;包围sizeof操作符的操作数。
3,优先级问题:.的优先级高于*;->操作符用于消除这个问题;[]高于*;函数()高于*
4,在C语言中,自动变量在堆栈中分配内存,但包含自动变量函数或代码块退出时,它所占用的内存便被收回。解决方法:返回一个指向字符串常量的指针;使用全局声明数组;使用静态数组;
显示分配一些内存,保存返回的值;
第三章
1,int (*foo())[]:返回的是一个指向数组的指针;
2,typedef是一种类型引入新的名字,应该用在数组,结构,指针以及函数的组合类型。可移植类型
第四章
1,C语言中的对象必须有且有一个定义,但它可以有多个extern声明。定义只能出现在一个地方:确定对象的类型并且分配内存,用于创建新的对象。声明可以多次出现:描述对象的类型
,用于指代其他地方定义的对象。声明相当于普通的声明,它所声明的并非自身,而是描述其他地方创建的对象。定义相当于特殊的声明,它为对象分配内存。
2,x=y;在当前环境里,符号x的含义是x所代表的地址称为左值,左值在编译时可知,左值表示存储结果的地方。符号y的含义是y所代表的地址的内容,称为右值,在运行时才知。
第五章
1,预处理器-》语法和语义检查器-》代码生成器-》汇编程序-》优化器-》链接器
2,动态链接的主要目的是把程序与特定的函数库版本中分离开来,由系统向程序提供一个接口,该接口保持稳定,不随时间和操作系统的后续版本发生变化。
3,动态链接文件的扩展名是.so,而静态库文件的扩展名是.a;通过-lthread选项,告诉编译链接到libthread.so,传给c编译器的命令行参数里并没有提到函数库的完整路径名及函数库目录中该文件的
完整名字。实际上,编译器被告知根据选项-lname连接到相应的函数库。
4,编译器期望在确定的目录找到库,在链接时使用-Lpathname和—Rpathname选项告诉链接器一些其他的目录。
5,观察头文件,确认所使用的函数库
6,可以在ld程序中使用-m选项,让链接器产生一个报告。使用ldd命令,列出可执行文件的动态依赖集,这条命令会告诉你动态链接程序所需要的函数库。
7,链接器把指令直接从文件拷贝到内存中(一般使用mmap())
8,可执行文件中段在内存中的布局:堆栈段(局部于函数的数据,保存局部变量,临时数据,传递到函数好着呢个的参数)-》BSS段(未初始化的数据)-》数据段(经过初始化的数据,经过初始化的全局和静态变量)-》文本段(可执行文件的指令)
9,c程序运行时的数据结构有好几种:堆栈,活动记录,数据,堆等。堆栈为函数内部声明的局部变量存储空间;进行函数调用时,堆栈存储与此有关的一些维护性信息。
第七章
1,虚拟内存通过页的形式组织,页是操作系统在磁盘和内存之间移动或进行保护的单位。在磁盘中有个特殊的交换区,用于保存从内存中换出的进程,交换区一般是物理内存的几倍,只有用户进程才会
换进换出。进程只能操作位于物理内存中的页面。
2,堆区域用于动态分配的存储,通过malloc分配,通过指针访问。堆中的东西都是匿名的,不能按名字直接访问,只能通过指针间接访问。堆内存分配的大小总是经过对齐是2的乘方。堆的末端有一个
称为break的指针来标识。当堆管理更多内存时可以系统调用brk和sbrk来移动break指针。
3,观察内存泄漏是两个步骤:首先用swap命令观察还有多少可用空间:/usr/sbin/swap -s;在一两分钟内建入该命令三到四次,看看可用交换区是否在减少或/usr/bin/*stat netstat,vmstat
发现不断有内存被分配且从未被释放。第二步是确定可疑进程:pa -lu;来显示所有进程的大小。
4,最终可能导致段错误的常见编程错误是:坏指针错误:在指针赋值前使用,向函数库传递一个坏指针,释放后仍然访问它的内容可以释放后赋值为nULL;越数组边界写入数据;
指针释放引起的错误:释放一个内存块两次,释放未曾分配的内存,释放仍在使用的内存,释放无效指针。
5,在遍历链表时正确释放元素的方式是使用临时变量存储下一个元素的地址。
第九章
1,数组下标的引用总是可以写成“一个指向数组的起始地址的指针加上偏移量”;在表达式中指针和数组是可以互换的,它们在编译器里的最终形式都是指针,都可以进行取下标操作。
2,编译器自动把下标值的步长调整到数组元素的大小。
3,把函数的形参的数组和指针等同起来是处于效率的考虑。
4,在c的多维数组中,最右边的下标是最先变化的这个约定称为“行主序”
第十章
1,a[i][j]:在内存中首先找到a[i]的位置,然后偏移[j]取得字符a[i][j]被编译器解析为:*(*(a+i)+j)
2,无法直接从函数返回一个数组,但可以让函数返回一个指向任何数据结构的指针。int (*func())[20];返回一个指向包含20个int元素的数组的指针。
第十一章
1,面向对象编程的特点是继承和动态绑定。c++通过类的派生支持继承,通过虚拟函数支持动态绑定。虚拟函数提供了一种封装类体系的实现细节的方法。
2,C语言允许用户定义新的类型(struct,enum)来支持抽象。封装:把相关的类型,数据和函数组合在一起。
3,类就是用户定义类型加上所有对该类型进行的操作。friend类的函数,不属于类的成员函数但可以像成员函数一样访问类的private和protected值
C专家编程
最新推荐文章于 2022-02-25 08:40:10 发布