您的位置:首页 > 编程语言 > C语言/C++

C语言深度剖析学习笔记

2013-03-28 00:58 507 查看
[align=center]C语言深度剖析学习笔记[/align] 这两天抽空看完了这本网络上很火的书《C语言深度剖析》,可能是因为下载的版本过于初级吧,阅读中发现了很多的错误,但总体来说,作者这本书中的知识点很具体很丰富,作者作为一名教师,把C语言课程能上的这样生动,已经很牛啦!麻雀虽小,五脏俱全,推荐大家看看,权当巩固下C语言知识。 以下是我在读这本书时记录下来的认为比较重要的地方,留待有时间了好好复习。1.使用register应注意的几点将变量保存在寄存器中速度非常快,但必须遵守以下限制:register变量必须是能被CPU寄存器所接受的类型。意味着register变量必须是一个单个的值,并且其长度应小于或等于整数的长度。而且register变量可能不存放在内存中,所以不能用取址运算符“&”来获取register变量地址。2.static用法(1)静态全局变量,作用域仅限于变量被定义的文件。其他文件即使使用extern也无法使用它,恶心吧。想要使用就得在它的定义前面再加上extern。(2)被static修饰的变量存在于内存的静态存储区域,所以程序执行过程中变量不会被销毁。(3)修饰函数,作用域仅限本文件,不必担心和其他文件的函数重名。3.关键字sizeof首先,sizeof不是个函数!!当sizeof计算变量a所占的空间时,不必非得加上括号。但是,当计算类型大小时,必须使用括号,否则无法编译。建议使用sizeof时都加上括号。值得注意的几个用法:int a[100], *ptr = a;那么sizeof(a)= 400, sizeof(ptr)= 4应该都没什么异议。但sizeof(&a)= 400, sizeof(*ptr)= 4大家也应该明白。a作为右值是数组a的始地址,&a也是数组a的始地址,sizeof(a) = sizeof(&a)= 400。除了在sizeof中不同外,其它情况下使用数组a会将a转化为指针使用。4.字符串中的结束符’\0’其实就是用int型的0给char赋值,在char中‘\0’= NUL,(int)‘\0’= 0;5.if判断语句的用法使用if判断flag变量的真假时,不要写成if(1 == flag)这种形式,因为我们不知道每个编译器是如何定义TRUE的值的。一定要写成if(flag)或if(!flag)的形式。先处理正常情况,再处理异常情况,并确保if和else子句没弄反。相信初学者经常犯这种错误。6.Switch时确保每个case语句结尾不要忘了加break,除非你想让多个case情况下该段代码都执行,当然这也是一种技巧。Case后面只能是整形或字符型的常量或常量表达式(字符型在内存中是作为整形存储的)。7. constconst修饰的变量只能在使用变量的地方使用,对于数组的声明中不能使用const变量作为数组长度,可以使用#define定义的字符值常量。8.Extern!!! 将数组的定义声明为相应类型的指针,会产生无法预计的后果。该指针的内容是原数组第一个元素,所以指向该元素代表的内存;将指针的定义声明为数组,数组第一个元素的内容便是某内存(未知)保存的该指针的地址,然后依次往后使用数组的后续元素,当然也错误!9.空结构体占用的内存大小为1B。因为内存中能处理的最小的数据类型所占用的内存单位为1B。10.柔性数组实在很少用,不掌握也无所谓。11.数组地址和数组指针的加减操作数组a,a是数组第一个元素的地址,a+1为a数组中第二个元素的地址。&a是数组a的地址,也就是a中第一个元素的地址,&a+1为数组后第一个元素的地址。因为&a是个数组指针,对该指针加1相当于在该地址上加上整个数组大小。12.数组a,((int)a)+1无意义,不能对其使用*操作符。13.枚举经常使用,可以规定变量的取值范围。枚举中的成员是常量。从第一个有赋值的声明处递增!!14.如何判断const修饰什么在int const *ptr; const int *ptr; int * cosnt ptr;const int * cosnt ptr;这几个声明最容易让人弄混。下面教大家一个容易理解的方法(大部分编译器也是这么理解的)。先去掉类型符int,然后,cosnt距离什么近就修饰什么。在int const *ptr中去掉int,const距离*近,修饰指针,指针为常量不可变。在const int *ptr中同样如此,所以他们含义相同;int * const ptr中const修饰ptr,说明指针指向的内容为常量,不可变。以后碰到const修饰变量,就这么推断!15.typedef的真正意思是给一个已经存在的数据类型(注意:是类型不是变量)取一个别名,而非定义一个新的数组类型。这个别名不能再和其它数据类型组合,例如typedef int int32; unsigned int32 a = 1;这种用法就是错误的。16.++、--操作符如果作为后缀是在碰到末尾的“;”后才执行自加自减操作。如果多个++在同一个语句里执行,C标准并没有给出规定,不同编译器做出不同处理!17.C语言声明的“贪心法则”:每一个符号应该包含尽可能多的字符。也就是说,编译器将程序分解成符号的方法是,从左到右一个一个地读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,直到读入所有字符或者读入后不再能组成一个有意义的符号。18.-a/b,和-a%b的值该如何理解假设c = -a / b; d = -a % b,那么c的符号和-a/b真实结果的符号相同,且c * b + d = -a;19.Const修饰的数据是有类型的,而define宏定义的数据没有类型。Define宏定义时不作任何类型检查。Const修饰的不是常量而是readonly的变量,const修饰的只读变量不能用来作为定义数组的维数,也不能放在case关键字后面。20.接续符“\”在一行的最后面,后面不能再有任何字符,哪怕空格!21.注释先于预处理指令被处理!(大概是因为怕预处理时define把注释中的内容替换了吧)所以不能用宏定义来开始或结束一段注释。22.宏定义#if中,必须对常量或常量表达式进行判断!!常量是在#define中定义的或者就是常量!23.在头文件包含时,或其它使用文件路径的地方,“.”代表当前目录,“..”代表上层目录。24.Int a[10]; Int (*p)= &a,这两句将p声明为一个数组的指针,&a实际上就是数组a的指针(数组指针)。p[2]表示从起始地址移动2个a[10],就相当于p+2,是吧!p[2][5]就表示向后移动两个a[10]后的那个数组中的第二个元素!如果一个指针ptr为数组指针,那么ptr[0]就为第一个数组,ptr[0][2]就为第一个数组中的第3个元素!同理可知ptr[2][3]是ptr指向的第三个数组(即以ptr+2 * sizeof(该数组)为始地址开始的数组)。25.当数组作为函数参数的时候,编译器总把它解析成一个指向其元素首地址的指针。当二维或二维以上的数组作为函数参数时,例int a[4][5][6]作为参数时可以被改写为int a[][5][6]或者int (*a)[5][6]。即可以省略第一维的大小,其余维数不可省略原因很简单,那是因为将第一维作为指针了,原理和一维数组传入函数时相同。26.Main函数内的变量不是全局变量,而是局部变量,只不过它的声明周期看起来和全局变量一样长而已。全局变量是在函数外部声明的。27.函数指针内保存的就是4byte的整形数据,就是函数的入口地址。函数指针和普通类型指针的本质相同。28.栈就是堆栈,堆和堆栈没关系。内存可分为三部分,静态区、栈、堆。静态区:保存自动全局变量和static变量(包括static的全局变量和static的局部变量)。静态区的内容在整个程序的声明周期都存在,由编译器在编译的时候分配。栈:保存局部变量。栈上的内容只在函数的范围内存在,当函数结束,这些内容被自动销毁。堆:由malloc系列函数或new操作符分配的内存。其生命周期由free或delete决定。没有释放之前一直存在直到程序结束。29. 使用malloc()申请0长度的内存时,返回一个正常的内存地址,但你无法使用这个地址。30.Free完之后一定要给相应指针直NULL,否则,有可能使用这个指针访问已释放的内存。这就是所谓的“野指针”!31.包括main函数在内,编译器默认的函数返回类型是int型。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: