ImageVerifierCode 换一换
格式:DOCX , 页数:115 ,大小:2.72MB ,
资源ID:2395289      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-2395289.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(C语言经典书籍总结合辑.docx)为本站会员(b****1)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

C语言经典书籍总结合辑.docx

1、C语言经典书籍总结合辑C和指针C专家编程C陷阱与缺陷C语言编程要点编程精粹-Microsoft编写优质无错C程序秘诀总 结指针和数组相关概念*字符与字符串的区别指针与数组1指针与数组2指针和数组的相同与不同用malloc为字符串分配存储空间时的注意事项作为常数的数组声明(c缺陷与陷阱3.3节.在其它部分有包含该节的知识点,了解or略过)字符串常量用字符串常量初始化指针和数组二维数组下标操作的相关概念指向一维、二维数组的指针array_name和&array_name的异同数组作为函数的参数时,不能通过sizeof运算符得到该数组的大小用strlen()求字符串的长度char * 和 const

2、 char *的兼容性问题空指针相关的问题NULL和NUL的区别未初始化的指针和NULL指针的区别理解函数的声明函数参数的传值调用函数指针作为函数参数的多维数组强制类型转换相关概念可变参数相关问题malloc()、calloc()、realloc()在程序退出main()函数之后,还有可能执行一部分代码吗?总线错误和段错误相关概念数字和字符串之间转换相关的函数*怎样判断一个字符是数字、字母或其它类别的符号?怎样将数字转换为字符串?怎样将字符串转换为数字?字符串以及内存操作相关函数*字符串拷贝和内存拷贝函数:strcpystrncpymemcpymemmovememccpybcopy字符串和内存

3、数据比较函数:strcmpstrcasecmpstrncasecmpmemcmpstrcollbcmp连接字符串的函数:strcatstrncat查找字符/字符串的函数:strstrstrchrstrrchrmemchr其它相关的函数:indexrindexstrlenstrdupmemsetbzerostrspnstrcspnstrpbrkstrtok数据结构及算法相关函数qsort()bsearch()lsearch(线性搜索)lfind(线性搜索)srand(设置随机数种子)rand(产生随机数)OTHER*什么是标准预定义宏?断言 assert(表达式) 相关概念连接运算符“#”和字符

4、串化运算符#有什么作用?注释掉一段代码的方法Typedef相关概念= 不同于 =词法分析中的“贪心法”运算符的优先级问题变量的存储类型及初始化相关概念左值和右值相关的概念变量的值和类型相关的概念怎样删去字符串尾部的空格?怎样删去字符串头部的空格?怎样打印字符串的一部分?结构的自引用结构的存储分配边界计算与不对称边界整数溢出返回整数的getchar函数更新顺序文件随机数的相关概念用递归和迭代两种办法解fibonacci字符与字符串的区别(c缺陷与陷阱1.5节)#include int main() char ch = abcdefghijklmnopqrstuvwxyz; char str =

5、abcdefghijklmnopqrstuvwxyz; printf(-%c-n%sn,ch, str );return 0;编译该程序可以通过,但是会产生警告;输出结过为:-z-Abcdefghijklmnopqrstuvwxyz / 在Dev-C+ 4.9.9.2编译环境中可以通过,但是在VC.0中通不过指针与数组1(c缺陷与陷阱3.1节)c语言中的数组值得注意的地方有以下两点:1、c语言中只有一维数组,而且数组的大小必须在编译期间就作为一个常数确定下来(C99标准允许变长数组,GCC编译器中实现了变长数组)。然而,c语言中数组的元素可以是任何类型的对象,当然也可以是另外一个数组。这样,要

6、仿真出一个多维数组就不是一件难事。2、对于一个数组,我们只能够做两件事:确定该数组的大小,以及获得指向该数组下标为0的元素的指针。其他有关数组的操作,哪怕它们乍看上去是以数组下标进行运算的,实际上都是通过指针进行的。换句话说,任何一个数组下标运算都等同于一个对应的指针运算,因此我们完全可以依据指针行为定义数组下标的行为。现在考虑下面的例子:int i;int *p;int calendar1231;上面声明的calendar是一个数组,该数组拥有12个数组类型的元素,其中的每个元素都是一个拥有31个整型元素的数组。因此,sizeof(calendar)的值是:3112sizeof(int)。考

7、虑一下,calendar4的含义是什么?因为calender是一个有着12个数组类型元素的数组,它的每个数组类型元素又是一个有着31个整型元素的数组,所以calendar4是calendar数组的第5个元素,是calendar数组中12个有着31个整型元素的数组之一。因此,calendar4的行为也表现为一个有着31个整型元素的数组的行为。例如,sizeof(calendar4)的结果是:31sizeof(int)。又如,p = calendar4;这个语句使指针p指向了数组calendar4中下标为0的元素。因为calendar4是一个数组,我们可以通过下标的形式来指定这个数组中的元素:i

8、= calendar47,这个语句也可以写成下面这样而表达的意思保持不变:i = *( calendar4 + 7 ),还可以进一步写成:i = *( *( calendar + 4 ) + 7 )。下面我们再看:p = calendar; 这个语句是非法的,因为calendar是一个二维数组,即“数组的数组”,在此处的上下文中使用calendar名称会将其转换为一个指向数组的指针。而p是一个指向整型变量的指针,两个指针的类型不一样,所以是非法的。显然,我们需要一种声明指向数组的指针的方法。int calendar1231;int (*monthp)31;monthp = calendar;i

9、nt (*monthp)31 语句声明的 *monthp 是一个拥有31个整型元素的数组,因此,monthp就是一个指向这样的数组的指针。monthp指向数组calendar的第一个元素。指针与数组2(c和指针.P141.)1、数组的名的值是一个指针常量,不能试图将一个地址赋值给数组名;2、当数组名作为sizeof操作符的操作数时,sizeof(arrayname)返回的是整个数组的长度,而不是指向数组的指针的长度;3、当数组名作为单目操作符&的操作数,取一个数组名的地址所产生的是一个指向数组的指针,而不是一个指向某个指针常量值的指针。4、指针和数组并不总是相等的。为了说明这个概念,请考虑下面

10、这两个声明:int a5;int *b;a和b能够互换吗?它们都具有指针值,它们都可以进行间接访问和下标操作。但是,它们还是有很大的区别的:声明一个数组时,编译器将根据声明所指定的元素数量为数组保留内存空间,然后再创建数组名,它的值是一个常量,指向这段空间的起始位置。声明一个指针变量时,编译器只为指针本身保留内存空间,它并不为任何整型值分配内存空间。而且,指针变量并未被初始化为指向任何现有的内存空间,如果它是一个自动变量,它甚至根本不会被初始化。把这两个声明用图的方法表示,可以发现它们之间存在显著的不同: a b? 因此,上述声明后,表达式*a是完全合法的,但表达式*b却是非法的。*b将访问内

11、存中某个不确定的位置,或者导致程序终止。另一方面,表达式b+可以通过编译,但是a+却不能,因为a的值是一个常量。#includeint main() /注意sizeof(num)的长度应该为10*4=40 int num = 0,1,2,3,4,5,6,7,8,9; printf( sizeof(num) = %dn, sizeof(num) ); /注意sizeof(str)的长度应该为11,包括字符串后面的0 char str = 0123456789; printf( sizeof(str) = %dn, sizeof(str) ); /注意sizeof(str1)的长度应该为10,不包

12、括字符串后面的0,但是,最好将字符串的最后一个字符设定为空 char str1 = 0,1,2,3,4,5,6,7,8,9; printf( sizeof(str1) = %dn, sizeof(str1) ); /&num的类型为int (*)10,表示的是一个指向长度为10的整形数组的指针 int (*ptoint)10 = # printf( sizeof(ptoint) = %d, (*ptoint)9 = %dn, sizeof(ptoint), (*ptoint)9 ); /&str的类型为char (*)11,表示的是一个指向长度为11的字符数组的指针,注意str数组的长

13、度是11,而不是10 char (*ptostr)11 = &str; printf( sizeof(ptostr) = %d, (*ptostr)9 = %cn, sizeof(ptostr), (*ptostr)9 ); /由于p指向的是数组num5,所以对下标取负值后,不会超出数组的正常取值范围 /该例子也说明了为什么下标检查在c语言中是一项困难的任务:下标引用可以作用于任意的指针,而不仅仅是数组名 /作用于指针的下标引用的有效性即依赖于该指针当时恰好指向什么内容,也依赖于下标的值 int *p = num + 5; printf( p-1 = %d, p0 = %d, p1 = %d

14、n, p-1,p0,p1 ); /下面的表达式中,num5和5num的值是一样的,把它们转换成对等的间接访问表达式,它们都等同于*(num + 5) /5num这个古怪的表达式之所以可行,缘于C实现下标的方法。对编译器来说,这两种形式并无差别 /但是,决不应该编写形如5num的表达式,因为它会大大的影响程序的可读性 printf( num5 = %d, 5num = %d n, num5, 5num ); getchar(); return 0;输出结果为:指针和数组的相同与不同(c专家编程.P199.)在实际应用中,数组和指针可以互换的情形要比两者不可互换的情形更为常见。让我们分别考虑“声明

15、”和“使用”这两种情况。声明本身还可以进一步分为3种情况:外部数组的声明;数组的定义(定义是声明的一种特殊情况,它分配内存空间,并可能提供一个初始值);函数参数的声明; extern,如extern char a; 不能改写为指针的形式 声明 定义,如char a10; 不能改写为指针的形式 数组 函数的参数,可以随意选择数组 在表达式中使用 的形式或者指针的形式 如c=ai,可以随意选择数组 形式或者是指针形式也既是:作为函数参数时、在语句或表达式中使用数组时,我们可以采用数组或者指针的任何一种形式,除此之外的其他情况下,指针和数组不要互换。下面就数组和指针相同的情况做详细的说明:规则1、表

16、达式中的数组名被编译器当作一个指向该数组第一个元素的指针。假如我们声明:int a10; int *p = a;就可以通过一下任何一种方式来访问ai:pi *( p + i ) *( a + i ) 事实上,可以采用的方法很多。对数组的引用如ai 在编译时总是被编译器改写成*(a+i)的形式,C语言标准要求编译器必须具备这个概念性的行为。编译器自动把下标值的步长调整到数组元素的大小。如果整型数的长度是4个字节,那么ai+1和ai在内存中的距离就是4。对起始地址执行加法操作之前,编译器会负责计算每次增加的步长。这就是为什么指针总是有类型限制,每个指针只能指向一种类型的原因所在,因为编译器需要知道

17、对指针进行解除引用操作时应该取几个字节,以及每个下标的步长应取几个字节。规则2、下标总是和指针的偏移量相同。把数组下标作为指针加偏移量是c语言从BCPL(C语言的祖先)继承过来的技巧。在人们的常规思维中,在运行时增加对c语言下标的范围检查是不切实际的。因为取下标操作只是表示将要访问该数组,但并不保证一定要访问。而且程序员完全可以使用指针来访问数组,从而绕过下标操作符。在这种情况下,数组下标范围检测并不能检测所有对数组的访问的情况。事实上,下标范围检测被认为不值得加入到c语言当中。还有一个说法是,在编写数组算法时,使用指针比使用数组更有效率。这个颇为人们所接收的说法在通常情况下是错误的。使用现代

18、的产品质量优化的编译器,一维数组和指针引用所产生的代码并不具有显著的差别。不管怎样,数组下标是定义在指针的基础上,所以优化器常常可以把它转化为更有效率的指针表达式,并生成相同的机器指令。规则3、在函数参数的声明中,数组名被编译器当作指向该数组第一个元素的指针。 在函数形参定义这个特殊情况下,编译器必须把数组形式改写成指向数组第一个元素的指针形式。编译器只向函数传递数组的地址,而不是整个数组的拷贝。这种转换意味着在声明函数的时候,以下三种形式都是合法的(同时无论实参是数组还是真的指针也都是合法的):my_function( int *turnip ) my_function( int turni

19、p ) my_function( int turnip200 ) 用malloc为字符串分配存储空间时的注意事项(c缺陷与陷阱3.2节)作为常数的数组声明(c缺陷与陷阱3.3节.在其它部分有包含该节的知识点,了解or略过)字符串常量(c和指针.P269.)当一个字符串常量出现在表达式中时,它的值是指针常量。编译器把该字符串的一份拷贝存储在内存的某个位置,并存储一个指向第一个字符的指针。我们可以对字符串常量进行下标引用、间接访问以及指针运算。“xyz”+1字符串常量实际上是个指针,这个表达式计算“指针值加上1”的值。它的结果也是个指针,指向字符串中的第二个字符y* “xyz”对一个指针执行间接访

20、问操作时,其结果就是指针所指向的内容。字符串常量的类型是“指向字符的指针”,所以这个间接访问的结果就是它所指向的字符:x。注意表达式的结果并不是整个字符串,而只是它的第一个字符。“xyz”2同样可以推断出上面这个表达式的值就是字符z。#include/接受一个无符号整型值,把它转换成字符,并打印出来/如果是打印16进值的数,可以用这种方法:putchar( 0123456789ABCDEF value % 16 )void binary_to_ascii( unsigned long value ) unsigned long quotient; quotient = value / 10;

21、if( quotient != 0 ) binary_to_ascii( quotient ); putchar( 0123456789 value % 10 );int main() /字符串常量实际上是个指针,这个表达式计算指针值加上1的值。它的结果也是个指针,/指向字符串中的第二个字符:y printf( %sn, xyz+1 );/对一个指针执行间接访问操作时,其结果就是指针所指向的内容。/字符串常量的类型是指向字符的指针,所以这个间接访问的结果就是它所指向的字符:xprintf( %cn, *abcdefg );/同样可以推断出上面这个表达式的值就是字符zprintf( %cn, a

22、bcdefg3 );binary_to_ascii( 1234567 ); getchar();return 0;用字符串常量初始化指针和数组 (c专家编程.P87.)定义指针时,编译器并不为指针所指的对象分配空间,它只是分配指针本身的空间,除非在定义时同时赋给指针一个字符串常量进行初始化。例如,下面的定义创建一个字符串常量(为其分配内存):char *p = “breadfruit”;注意只有对字符串常量才是如此。不能指望为浮点数之类的变量分配空间,如:float *pip = 3.14; /*错误,无法通过编译*/在ANSI C中,初始化指针时所创建的字符串常量被定义为只读。如果试图通过指

23、针修改这个字符串值,程序会出现未定义的行为。在有些编译器中,字符串常量被存放在只允许读取的文本段中,以防止它被修改。数组也可以用字符串常量进行初始化:char a = “gooseberry”;与指针相反,由字符串常量初始化的数组是可以修改的。比如下面的语句:strncpy( a, “black”, 5 );将数组的值修改为“blackberry”。#include#includeint main(void) char *p = this is a example; /char *pi = 3.14; /这样定义是错误的,无法通过编译 /p0 = T; /修改该字符串常量时,编译是没问题,但是

24、运行时会出现异常 char a = gooseberry; strncpy( a, black, 5 ); printf(%sn, p ); printf(%sn, a ); return 0;二维数组下标操作的相关概念(c和指针.P156.)指向一维、二维数组的指针(c和指针.P158.)array_name和&array_name的异同前者是指向数组中第一个元素的指针,后者是指向整个数组的指针。char aMAX; /*array of MAX characters*/char *p = a; /*p为指向数组的指针*/ char *pa = &a; /*该语句是不正确的,pa的类型为ch

25、ar *,而&a的类型为char (*)MAX*/char (*pb)MAX = &a; /*该语句是正确的,pb的类型为char (*)MAX*/#includevoid main()char a5 = a,b,c,d,0; char *p = a; /运行下面这句后, vc6.0 提示的错误为:cannot convert from char (*)5 to char *,&a的类型应该是指向一个数组的指针/char *pa = &a; /所以,应该定义一个指向相同类型和大小的数组的指针来获得“&a”的值char (*point_to_str)5; point_to_str = &a; p

26、rintf(%dn%dn,&p, &point_to_str); printf(%sn%sn, p, point_to_str);运行结果为:12450441245040abcdabcd数组作为函数的参数时,不能通过sizeof运算符得到该数组的大小不可以。当把数组作为函数的参数时,你无法在程序运行时通过数组参数本身告诉函数该数组的大小,因为函数的数组参数相当于指向该数组第一个元素的指针。这意味着把数组传递给函数的效率非常高,也意味着程序员必须通过某种机制告诉函数数组参数的大小。为了告诉函数数组参数的大小,人们通常采用以下两种方法:第一种方法是将数组和表示数组大小的值一起传递给函数,例如mem

27、cpy()函数就是这样做的: memcpy( dest,source,length );第二种方法是引入某种规则来结束一个数组,例如在C语言中字符串总是以ASCII字符NUL(0)结束,而一个指针数组总是以空指针结束。请看下述函数,它的参数是一个以空指针结束的字符指针数组,这个空指针告诉该函数什么时候停止工作: void printMany( char *strings ) inti = 0; while( stringsi != NULL ) puts(stringsi+); C程序员经常用指针来代替数组下标,因此大多数C程序员通常会将上述函数编写得更隐蔽一些: void printMany

28、( char *strings ) while( *strings ) puts(*strings+); 尽管你不能改变一个数组名的值,但是strings是一个数组参数,相当于一个指针,因此可以对它进行自增运算,并且可以在调用puts()函数时对strings进行自增运算。用strlen()求字符串的长度(c和指针.P159.)库函数strlen的原型为:size_t strlen( char const *string );strlen返回一个类型为size_t的值。这个类型是在头文件stddef.h中定义的,它是一个无符号整型类型。在表达式中使用无符号数可能导致不可预期的结果。例如,下面两个表达式看起来是相等的:if( strlen(str1) = strlen(str2) )if

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2