学习C语言100问1223.pdf

上传人:得****3 文档编号:83528269 上传时间:2023-03-31 格式:PDF 页数:19 大小:1.09MB
返回 下载 相关 举报
学习C语言100问1223.pdf_第1页
第1页 / 共19页
学习C语言100问1223.pdf_第2页
第2页 / 共19页
点击查看更多>>
资源描述

《学习C语言100问1223.pdf》由会员分享,可在线阅读,更多相关《学习C语言100问1223.pdf(19页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、学习 C 语言 100 问 问题 1:什么是分程序(复合语句)?分程序是指一对大括号之间的一段 C 语言程序。每一个 C 函数的函数体都是包括在一对大括号中,switch 语句所有取值情况的列举也是包括在一对大括号中,以此可以看出分程序在 C 语言中使用非常广泛,用户也可以根据需要自己组织分程序(更多的是程序功能的需要),它在 C 程序中的功能相当于一局部程序块,其间可以定义变量,这种变量称为局部变量,只能定义在分程序的开始部分,变量的有效范围是分程序内部。如果局部变量与分程序以外的变量重名,在本分程序内部,该局部变量对外面的同名变量进行屏蔽,另外提示一点的是,一般不用分程序来保存变量,例如:

2、#include int test=5;void main()int test=10;void fun1();/*-5-*/fun1();printf(“2-%dn”,test);/*-10-*/int test=15;printf(“3-%dn”,test);/*-15-*/void fun1()printf(“1-%dn”,test);问题 2:什么情况下用 switch 语句比 if 语句的多重嵌套更适合?如果有两个以上基于同一个数字型变量(整型变量,字符型变量,枚举类型变量等)的条件表达式,尤其是对于作为判断的数字型变量的取值很有限,且对每一个不同的取值,其所做的处理也不一样的情况,最

3、好使用一条 switch 语句,这样更易于阅读各维护。这里有两点需要注意就是,第一就是用于作为判断条件的变量一定要是数字型的,另一点就是所有的判断条件都是基于同一个数字变量,而不是多个变量。例如:有如左下的 if 嵌套更适合用右下的 switch 语句表达。char grade;if(grade=A)printf(“85100n”);else if(grade=B)printf(“7084n”);else if(grade=C)pritnf(“6069n”);else if(grade=D)printf(“60n”);else printf(“errorn”);switch(grade)cas

4、e A:printf(“85100n”);break;case B:printf(“7084n”);break;case C:printf(“6069n”);break;case D:printf(“60n”);break;default:printf(“error”);break;问题 3:switch 语句必须包含 default 分支吗?回答是否定的。但是为了逻辑上的严密性,一般应写 default 分支,这样在出现所有的 case子句以外的取值时才不至于难以确定其错误所在,例如象上面的例子,如省略了后面的default 子句,而用户如输入的是除 A,B,C,D以外的其他字符时,程序不做

5、出任何反应,而这本身是一种非法输入。问题 4:switch 语句的最后一个分支可以不要 break 语句吗?每一个 case 分支后面是否必须要加 break 语句?两者的答案都是“不”。大家知道,在 switch 语句中,如果作为条件判断的数字表达式的值与某一个 case 后面的取值相等,则以该 case 分支语句作为入口顺序执行后续语句,如遇上break 语句,则结束 switch 语句的处理,转而处理 switch 语句的后续语句,根据这个道理显然最后一个分支中的 break 语句可以省略,因为无论是否有 break 语句,此时都会结束 switch语句的处理。问题 5:怎样判断循环是否

6、提前结束?在多循环条件下,又如何知道是因为哪个条件不满足而使循环提前结束的?解决这种问题通常是在循环语句的后面再用一个或多个判断语句检查循环变量的取值,从而确知循环是正常结束还是提前结束,如循环条件是由多个循环变量构成,则可以对各个变量分别进行判断。例如:#include void isprime(int num)int s;for(s=2;ssqrt(num)return(1);else return(0);以上的例子用于判断给定的数是否为素数,函数中的循环语句正常结束是当 s 的取值大于给定数的平方根,但只要该数能够被某一个大于 1 而小于其平方根的数整除,即说明该数不是素数,循环提前结束

7、,于是在循环语句后面加一个判断,以得出正确结果。问题 6:什么叫左子值?数组名为什么不能作为左子值?左子值是指可以被赋值的表达式,即可以出现在赋值符号的左侧的表达式。同理出现在赋值符号右侧的称为右子值,每一个赋值语句都必须有一个左子值和一个右子值。左子值必须是内存的一个存储单元(在程序中通常表现为一个变量),而不能是一个常量。我们知道数组名在 C 语言中,代表的是数组所分配的存储单元的起始地址,而 C 语言中数组不可以在程序运行的过程进行移动,也就是说,数组一旦定义,其所占据的存储单元是固定的,也即他的起始地址也是固定不变,所以 C 语言在的数组名被当作是一个常量,也因此不能作为左子值。问题

8、7:+var 和 var+有什么区别?“+”运算符在 C 语句中的使用可以说多得不能胜数,但是要真正掌握它的运算却也并非易事,尤其是在多个运算符混合使用的情况下更是如此。“+”有前辍运算(+var)和后辍运算(var+)两种,大家都知道前者在表达式中是先把 var 加 1,而后引用 var 的值,后者是先引用 var 的值,而后 var 加 1,但在如下的运用中,就很难用这种规则来解释了:如:int x=10;y=x+x+;经以上运算 y 的值是多少呢?答案是 20,这里首先要确定各运算符的运算关系,按 C 语言确定运算符的规则(从左至右取尽量多的字符构成一个运算符),以上表达式相当 y=(x

9、+)+(x+),其中有两个后辍运算的自加运算,值得注意的是,引用时先把 x 的值在整个表达式中使用,而后进行两次加 1 操作,所以 y 后来的取值为 20,而 x的值为 12,不理解的话,很容易得出 y 的值最后是 21 的错误结果。再如:int x=5;printf(“%d,%dn”,x+,x+);输出的究竟是“5,6”,或“6,5”,还是“5,5”,再或者是其他取值呢?按照一般的思路要得出正确结果还是颇费周折的,正确结果是“6,5”,这里牵涉到 C 语言实参的求值顺序(自右至左计算各实参表达式)。问题 8:变量存储在内存中的什么地方?变量名是一个符号地址,代表内存中的某个内存单元,那么它究

10、竟存储在什么位置呢?对于一般程序设计人员,并不需要具体知道变量的存储位置,但应该根据变量的存储属性判断变量的存储区域。第一种是在函数外部定义的变量(全局变量或静态外部变量)和在函数内部定义的 static 变量,其生存期是程序运行的全过程,这些变量被存储在数据段中。数据段是在内存中为这些变量留出的一段大小固定的空间。第二种是在函数内部定义的 auto 变量(不加关键字 static 的变量)的生存期从程序开始执行其所在的程序块代码时开始,到程序离开该程序块时为止,即定义该变量的函数的部。作为函数参数的变量只在调用该函数期间存在。这些变量被存储在栈中。栈是内存中的一段空间,开始很小,以后逐渐自动

11、增大,这个界限由系统决定,并且通常非常大,因此程序员不必担心用尽栈空间。第三种是内存空间实际上并不存储变量,但是可以用来存储变量所指向的数据。如果把调用malloc()函数的结果赋给一个指针变量,那么这个指针变量将包含一块动态分配的内存的地址,这块内存位于一段名“堆(heap)”的内存空间中。堆开始时也很小,但当程序员调用malloc()或 calloc()等内存分配函数时它就会增大。堆可以和数据段或栈共用一个内存段,也可以有它自己的内存段,这取决于编译选项和操作系统。问题 9:使用 register 变量的意义何在?有什么用途?register 作名词的本义是“注册,寄存器”的意思,在程序中

12、如果用 register 修饰定义变量,表示将该变量保存在 CPU 的寄存器中,显然可以加快访问速度,但也不可以随意使用,而有以下几点限制:第一,register 变量必须是能被 CPU 寄存器所接受的数据类型,如不能把一个组合类型的变量指定为 register 变量。第二,因为 register 变量保存在 CPU 中,显然不应该用取地址运算符“&”来获取变量的地址。除去以上的限制外,也并不是说我们尽可能地多地定义 register 变量就能加快程序的运行速度,毕竟 CPU 中寄存器是有限的,如果你把变量指定为 register 变量,意味着可用于别的用途的寄存器就减少了,如程序运算产生的中

13、间结果,它们的应用又很频繁,在寄存器不足的情况下,只好借助于内存,这样反倒会降低程序的运算速度。在现今的 C 版本中,大多已没有定义 register 变量的必要,因为编译程序忽略 register 修饰符,而根据寄存器的使用情况和变量的情况决定是否把变量解释为 register 变量。问题 10:浮点数比较是否可靠?众所周知,计算机只能表示离散的数据,而浮点数是连续,任意两个浮点数之间都有无限多个浮点数的存在,所以浮点数是计算机编程中的一个盲点。由于浮点数很难对付,因此比较一个浮点数和某个值是否相等或不等通常是不好的编程习惯。但是,判断一个浮点数是否大于或小于某个数就安全多了。例如:如果你想

14、以较小的步长依次使用一个范围内的数字,你可能编写这样一个程序:#include main()float f;for(f=0.0;f!=70.0&f71.0;f+=0.007);printf(“f is now%gn”,f);然而,舍入误差可能导致 f 的值永远不等于 70.0,这样,循环会跳过 70.0。加入不等式“f71.0”变是为了防止在这种情况下程序继续运行很长时间。一种安全的做法是用不等式“f71.0”作为条件来终止循环,例如:float f;for(f=0.0;f0;f+=0.007);问题 11:说明一个变量和定义一个变量有什么区别?说明一个变量意味着向一个编译程序描述变量的类型,

15、但并不为变量分配空间。定义一个变量意味着在说明变量的同时还为变量分配存储空间。在定义一个变量的同时可以对变量进行初始化。一个变量可以被说明多次,但只能被定义一次。因此,不应该在头文件中定义变量,因为一个头文件可能会被一个程序的多个源文件包含。函数说明和函数定义也有类似的性质,当然不是说头文件中也不应该定义函数。问题 12:为什么在定义变量的时候应该说明变量的数据类型?数据类型是变量的一个重要的属性。不同的数据类型通常代表所定义的变量所占据的内存长度不同,编程时应该根据你所要的变量的取值范围选择一个合适的数据类型,例如:同样是作为循环计数变量,如果只循环 100 次,则可以选择循环变量的类型为字

16、符型(char),而在循环次数为 50000 次的时候,则应该选择循环变量的类型为长整型。此外,不同的数据类型往往也代表其所属类型可以参加的运算也不同。比如:整型变量可以有取模(%)、按位与(&)等运算,而浮点数则不具有这些运算。因此,编程时也应该根据变量所要参加的运算而选择相应的数据类型。问题 13:怎样使用宏定义(#define)?使用宏定义有什么好处?宏定义(#define)是一种预处理指令,在程序中用字符串(宏体)来被定义的宏名。有以下几点好处:第一,在输入源代码时,可省去许多键入操作,因为宏名往往比宏体要短。第二,因为宏只需定义一次,但可以多次使用,而且宏名往往代表一定的含义,所以使

17、用宏能增强程序的易读性和可靠性。第三,使用宏不需要额外的开销,因为宏所代表的代码只在宏名出现的地方展开,因此不象函数调用会引起程序跳转,宏展开不会引起程序跳转。第四,宏的参数对类型不敏感,因此你不必考虑将何种类型的数据传递给宏。宏虽然有诸多好处,但在使用也应该小心行事,尤其要注意以下几个方面:第一,在宏名和括起来的参数的括号之间绝对不能有任何空格类字符。第二,为避免在宏展开时产生歧义,宏体也应该用括号括起来。第三,对传递给宏的实参要千万小心,尤其是中把自增(减)变量作为参数传递给宏时。问题 14:可以用#include 指令包含扩展名不是“.h”的文件吗?回答是肯定的。可以用#include

18、命令包含任何一个文件。如果一个程序是由多个源程序文件所构成,用在一个源程序文件中使用#include 把其它程序文件都包含进来的方法是解决多文件程序的一种有效方法。当然,为了程序的可读性考虑,最好不要把不以“.h”为扩展名的文件用#include 命令包含进来,这样不容易区分哪些文件是用于编译预处理的。问题 15:在程序中加入注释有什么好处?注释作为一种被编译程序所忽略的说明性文字,往往被初学编程人员所忽视,认为它对于程序的功能没有任何作用,不加并没有损害,所以往往很少使用注释,这种看法是完全错误的。适当使用注释至少有以下两个方面的好处:第一,在软件技术相对滞后的今天,为了开发软件的需要,大量

19、的程序除了要能在计算机上运行外,出于种种原因,还需要程序源代码能够让编程人员读懂,而这本身是一件非常费力的工作,此时,注释的作用就不可低估了,有无良好的注释成了程序能不能读懂的关键点之一,这也现代源程序文档化要求的一个重要方面。第二,注释还可以为程序调试带来很大的方便。无论是多么有经验的程序人员,他编制的程序都不可能一次即保证完全正确,也因此需要对程序进行调试。调试工作的第一步是查错,这也是一件很费力的工作,往往是按模块分部进行。如怀疑某模块有错时,可以先将原来的模块注释掉,加入一个新编模块,如错误消失,则说明原来的模块确实有问题,此时才将原来的模块删除。问题 16:怎样检查一个符号是否已经被

20、定义?利用预处理指令#ifdef 可以检查一个符号是否已被定义,例如,在指针一节中,你不能确切知道 NULL 这个符号是否已经有定义,你可以用如下的一段程序实现这一点:#ifdef NULL#undef NULL#endif#define NULL(void*)0 这里,首先检查 NULL 符号是否已被定义,如果已有定义,则取消原来的定义,然后重新定义 NULL 符号。问题 17:什么是变量的间接引用?用变量名对变量的值进行引用的方式称为变量的直接引用。对指向变量或内存中的任何对象的指针来说,指针就是对变量值的间接引用。如果 p 是一个指针,p 的值就是其所指向的对象的地址;*p 的值就是其所

21、指向的内存单元的值。值得注意的是,用指针间接引用变量的值时,一定要明确知道指针的当前指向,断不可以随意通过指针间接引用而修改一个内存单元的值。如:int*p,a;*p=5;的做法就是很危险的,指针 p 当前的值不知道的情况下,它既可能指向用户程序区,也可能指向别的用户的程序区,还有可能指向操作系统区,盲目修改可能会带来严重后果。问题 18:什么是空指针?在指针和链表中用的非常广泛的空指针,表示的是不指向任何对象的一种指针,其值定义为NULL,它是在头文件“stdio.h”中定义的一个宏,其值与任何有效指针的值都不同,NULL是一个纯粹的零,它可能被强制转换为 void*或 char*类型。即

22、NULL 可能是 0 或(void*)0等。值得注意的是,绝对不能间接引用一个空指针,否则,你的程序可能会得到一个毫无意义的结果,或得到一个全部是零的值,或者会突然停止运行。问题 19:什么是 void 指针?void 指针一般称为通用指针,千万要与空指针严格区分,void 指针指向某个对象,但该对象不属于任何类型,但之所以称它为通用指针,是因为任何时候你都可能用其它类型的指针来代替 void 指针或者用 void 指针来代替其它类型的指针,如:函数 malloc()的返回值是void 类型,你可以在程序中将它的返回值赋给任何类型的指针。问题 20:两个指针可以相减吗?从一般意义上讲,回答是可

23、以。但作为一种编程工具,在程序中做任何事都得考虑其物理意义,两个指向不同类型对象的指针其相减就没有任何意义,故不应该做减法,同样不是同一组相关单元的两个指针其相减也没有任何意义,这就象问人家两个不同街道的两个门牌号之间相差多少个门牌号一样,是没有任何价值的,因此真正有意义的两个指针相减,只是在当两个指针指向相关的同类型的对象时,通常是数组,才对它们进行相减,其值为两个指针所指向的对象之间相差的同类型的对象的个数,即数组元素的个数。问题 21:数组的尺寸可以在程序运行时才确定吗?在 C 语言中,回答是肯定的,也就是说 C 语言不可以定义动态数组,数组的大小必须是在程序编译的时候就已经确定。可能这

24、样会给程序的灵活性带来一定的影响,但动态数组的定义会得程序的运行速度的降低。如果你确实事先难以确定数组的大小,其实 C 语言还是可以帮你实现的,那就是我们可以定义一个指针,然后调用 malloc()或 calloc()函数从堆中为这个数组分配内存空间,如:main()int*pa,num;scanf(“%d”,&num);pa=(int*)malloc(num*sizeof(int);问题 22:malloc()函数与 calloc()函数有什么区别?这两个函数都可以用来分配动态内存空间,但两者除了调用时的参数的数目不同以外,还有一点重要的区别,那就是 malloc()函数不能初始化所分配的内

25、存空间,而 calloc()函数会将所分配的内存空间的每一位都初始化为零。这样一来,用 malloc()函数所分配的空间,如果原来没有使用过,则其中的每一位都是 0,但如果这部分内容曾被分配、释放和重新分配,则其中可能遗留原有的数据。用 calloc()函数所分配的空间,无论以前是否使用过,都将初始化为零。所以在使用中,程序员应该根据你的实际需要选择相应的函数,除此外,从使用的角度看,这两个函数没有太大的区别。问题 23:什么叫做内部函数?怎样说明?只在定义某函数的程序文件中才能调用的函数称为内部函数。与变量不同,函数的默认属性是外部的,即可以被其他程序文件中函数所调用,因此为了说明一个函数是

26、内部函数,在定义该函数或说明该函数时应该加修饰符 static,如:/*文件 1.c*/#include“stdio.h”static void sort(int*a,int n);void select(int*a,int n,int num);void sort(int*a,int n)int j,k;void select(int*a,int n,int num)int k,mid;sort(a,n);在“文件 1.c”中,函数 sort 就是内部函数,它只能在该程序文件中调用,而不能在其他程序文件中调用,而函数 select 就是外部函数,它可以在其他程序文件中调用。问题 23:为什么

27、要说明函数原型?函数原型提供函数调用时所需的参数个数及各参数的类型,编译程序就据此检查函数调用时给定的实参是否符合要求。当然,如果函数定义总在函数调用处之前,可以不必说明函数原型,但是,因为 C 程序可以编制得非常大,函数调用之处与函数的定义之处可能相隔非常之远,这样编程时每次都去参考函数定义处的参数的数目和类型,其不方便之处显而易见;如果使用函数说明,则因为可以与调用处相隔很近(因为函数可以说明多次)。在多程序文件程序中尤其如此,往往是在程序的开头对程序中所使用到的函数都进行说明,以便查找。值得注意的是,如果函数定义在后,调用在前,应务必在调用前对函数原型进行说明。问题 24:一个函数可以有

28、多少个参数吗?对于一个函数的参数的数目 C 语言并没有明确的说明,但参数不应该太多,这也是编程人员应该遵循的一种程序风格。因为函数参数在调用过程中存放在堆栈中,参数数目太多的情况下,意味着更多的数据需要保留,从而降低了函数的运行速度,从另一个方面说,参数越多编程的难度显然也会加大,有利于发现程序在错误,因此,通常应该尽可能地减少参数的数目,如果实在要使用很多的参数时,可以考虑用一个结构体类型变量来容纳这些参数,用这个结构体类型的变量来作为函数的参数。问题 25:如果一个函数没有返回值,是否需要加入 return 语句?如果一个函数没有返回值(函数原型的“返回值”类型为 void),此时没有必要

29、加入 return语句,但函数执行如可能引起严重错误(可以预料的),则应该预设 return 语句返回,另外注意一点的是,不应该在函数中设多处 return 语句,这程序编程习惯不可取,而应该让函数的退出操作尽量集中和简洁(必要时不妨使用 goto 语句)。需要注意的是,函数没有返回值不是在函数定义时缺省返回值类型的情况,其实应该对所有函数都明确给定其返回值类型,包括返回值为空(即没有返回值)。问题 26:用数组名或指针作为函数的参数其实质是什么?众所周知,数组名做为一个符号地址其所代表的是数组所分配的内存单元的起始地址,而指针本身就是地址,用这两者作为函数的形参时,它们是等价的,都是相当于用

30、指针变量作为函数的形参(也正因于此,用数组名作函数形参时,可以进行自增、自减等运算);用这两者作为函数的实参时,按 C 语言中“用值传递”参数传递原则,即是把实参数组名(指针)的值传递给相应的形参(因传递的值是一个地址,故有些资料介绍这是一种“地址传递”),也就是说,经过参数传递后,形参数组名(指针)与实参数组名(指针)指向同一内存单元,故此,如果在函数中通过形参数组名(指针)的引用可以修改实参数组名(指针)所代表的数组元素的值。问题 27:exit()与 return 有什么不同?用 exit()可以退出程序的处理而把控制权交回操作系统,而用 return 语句可以结束当前函数的处理,控制权

31、交回调用该函数的函数(即所谓主调函数)。前者通常是用在程序中可能发生的不可忽略的错误时使用,如在文件打开出错时,我们通常用 exit()来退出程序的处理,而后者是作为函数运行的正常情况或非严重错误时使用,但如在 main()中使用 return语句,其效果与 exit()没有多大差别。问题 28:为什么要谨慎对待紧跟在数组后面的元素?C 语言不检查数组下标的越界,这是众所周知的事,在给程序员带来了一定的灵活性的同时,却也给程序编制留下了一个不小的陷阱,要切记 C 语言的数组元素下标是从 0 开始的,也就是说下标值为数组长度的元素已经不是数组的元素,例如:int a10;a10=5;如果不是特意

32、安排,象这种赋值在程序中就不应该出现。在定义一个数组后,系统为其分配相应的存储区间,而数组后面的存储单元既然不是数组存储区内,系统可能会将它分给其他的程序或系统程序使用,显然,如果你在程序随意将这些单元进行修改,可能会影响其他程序甚至系统程序,从而产生不可预料的后果,所以对紧跟数组的存储单元应该谨慎而又谨慎。问题 29:通过指针和数组下标方式都可以访问数组元素,哪一种方式更好?首先让我们看一下两种引用方式的引用过程。例如:int a10,*p,k;/*方式 1*/for(k=0;k10;k+)printf(“a%d=%dn”,k,ak);/*方式 2*/for(p=a,k=0;pa+10;p+

33、,k+)printf(“a%d=%dn”,k,*p);上面两种方式都可以输出数组的全部元素值,哪一个效率更高呢?其中,方式 1 通过下标方式引用,引用一个存储单元的值首先应该知道该存储单元的地址,因此,应先通过 ak计算出第 k 元素的地址,其计算方法是:数组的首地址+k*数组元素的长度,从这里可以看出,第次计算都要用一次乘法,而乘法运算是比较慢的;方式 2,指针 p 指向相应元素,换句话说就是 p 的值本身就是第 k 元素的地址,每循环一次都往下移动一个元素,因此不需要每次都进行一次乘法运算,从这个角度看,用方式 2 引用,即使用指针引用数组元素更好。但因为方式 1 直观,对于初学者来说,应

34、该是一种值提倡的主要方式,再说,相对程序中的其它操作,如 I/O 操作、函数调用,这样的开销是微不足道。问题 30:什么是“位屏蔽”?它有什么作用?如何设置“位屏蔽”?位屏蔽的含义是从包含多个位集的一个或一组字节中选出指定的一个位或几个位。通常用在需要根据某(些)位的取值来决定程序的流向的情况下。常在下面几种方式:1屏蔽某些位,即将需屏蔽的位清“0”,而保留有用的位进行判断,用按位与运算。如:检查变量 flag 的最低位是否为 1,可以用表达式:flag&1,然后再判断表达式的值是 0或 1 来得出其最低位为 0 或 1 的结论,也可以根据这个结果来形成不同的程序分支。2设置某些位,即将特定位

35、置“1”,其他位不变,用按位或运算。如:将变量 flag 的低 4 位全置 1,其他位不变,可以用表达式 flag=flag|0 xf。3将特位取反,即原来是 0 变成 1,而原来是 1 变成 0,用异或运算。如:将变量 flag 的 47 位(从 0 开始计数)取反,可以用表达式 flag=flag 0 xf0 问题 31:什么是算法的有穷性?如何判断算法是否符合这个要求?所谓算法有穷性是指一个算法应包含有限的操作步骤,即在执行有限操作后算法结束。对于初学者来说,这是一个常见错误,具体说,就是容易编制一些死循环。要判断算法是否符合有穷性要求,没有一个确定的方法,但也有些规律可循,以下是笔者的

36、一点经验:首先,当然还是应该多积累经验,你可能觉得这是句废话,有经验了还能出现此类错误吗?但你不觉得经验的积累绝不是拼命上机实践就能有效获得的,而应该讲究方法。我以为,倒不急于上机实践,而是在上机前先认真地阅读自己或他人的程序,做到心里有底,对程序有了一定的了解后再上机实践,尤其是其中的循环部分,要能看出其入口是什么,循环出口又是什么,注意循环控制变量的变化情况,经过一番考虑后,再上机实践,你就能做到举一反三,事半而功倍。其次,在程序中加入适当的检测语句,也就是在程序调试过程中,在程序的适当位置加入一些“无用”的语句(一般就是加入一些简单的输出语句),尤其是在循环体内加入检测语句,这样就可以跟

37、踪程序的执行,出现问题时就更容易发现。再次,如果不慎还是出现了死循环,也不要束手无策,C 语言还是考虑到了这种情况的存在,你可以用 CTRL+C 组合键来终止你程序的执行(当然,C 语言的本意倒未必就是为此而设),有时 CTRL+C 也没有任何作用,此时你可以用 CTRL+Break 组合键中断你的程序的执行,此时问题一般会迎刃而解,再不行只好重新启动机器了,可惜你对程序所做的修改完全丢失。问题 32:什么是符号常量?有什么好处?什么时候使用符号常量?符号常量作为常量的一种形式,其值在程序运行过程中是不可以改变的(注意:是不可以改变,而不只是没必要改变),通常是用#define 命令把一个字面

38、常量或表达式(当作字符串看待)定义为一个标识符。符号常量的好处主要在于两个方面:一方面,标识往往有一定的含义,所以符号常量比字面常量含义更清楚;二方面:修改符号常量值比逐个修改字面常量的值要方便得多,也因此而减少了同一常量其值不一致的机会。使用符号常量的时机也很难找出一个确定的标准,但以下两种情况笔者认为较适合使用:第一,就是对于在程序中经常要修改的常量,例如:定义的数组时,数组的大小很难确定的情况下,可以事先把数组大小定义为一个符号常量;第二,就是在在程序中多处使用的常量,这样才可以体现其第二方面的好处。另外,符号常量的定义应该在引用它的程序文件的开头定义,不应该想到使用了,就便在某处定义符

39、号常量,这样会使程序变得晦涩。问题 33:如何记忆各数据类型的取值范围?了解各数据类型的取值范围,尤指整型数据的取值范围,对于编写正确的程序是很重要的。不同的系统,即使同一种数据类型其取值范围可能并不一样,但常用的微机上的 Turbo C2.0,还是有一个较为确定的范围的。只是要记下取值范围对于初学者似乎也不容易,这里笔者介绍自己一点经验,首先要确定最一般的 int 型的取值范围,你只要知道它在内存中占几个字节就很容易得出正确结果,在 Turbo C2.0 中,它占两个字节,也就是 16 个二制位,又因为最高位表示符号位,所以用于表示数值的数位就是 15 位,自然可以最多表示 215个数(你可

40、以类比 5 位的 10 进制数可以表示多少个数,难道不是 105个吗?),因为有正负之分,所以一共可以表示 2*215个数,所以它的取值范围是-215215-1 也就顺理成章了,如果是只表示无符号数,也就是最高位失去符号位的含义,可以用 16 位表示数值,范围自然也就成了0216-1 了,其他数据类型范围都可以此类推,如长整型因其点 4 个字节,所以带符号长整型的范围为-231231-1,无符号长整型范围为 0232-1,而短整型与一般整型相同。可能你连各类型占的字节数你都不想记,那我说你可以不必学习 C 语言了,因为你肯定学不好。再说你如暂时忘了其所占字节数,也可以用 sizeof(数据类型

41、名)得到该类型在内存中所占字节数。对于浮点型,我们都不必太关心其取值范围,而就关心它的数据表示精确度,这个只好靠记忆了。问题 34:如何有效使用反义字符?反义字符作为字符常量的一种,首先不要在内心里排斥它,觉得掌握它难,试想你如不使用 n,你如何让程序按你的要求在适当的时候换行呢?在你对它不无亲切感之后,掌握它也就不难了,你会发现其实还是有相当的规律可循的,大家都知道,所有字符在机器内部都是以二进制的形式存在,也就是常说的 ASCII,而转义字符无非是直接使用字符的 ASCII 来引用相应的字符罢了,不是来得更直接吗?这就是“”加一个两位的十六进制数字或 3 位的八进制数字的由来,至于“n,t

42、,b”等,是因为其常用,而用一个特定字母来表示,只是为了更省事而已,不是也可以用前一种方式来表示的吗?问题 35:如何看待字符串常量后面的0?在 C 语言中,0作为字符串结束的标志是从所周知的事,但为什么这样呢?大家也知道 C语言不提供字符串这样一种专门的数据类型,表示字符串时通常是用一个指针或一个字符数组,而指针或字符数组名只表示的字符串在内存中的起始地址,无法具体知道字符串究竟占几个字节,在正因为此,才需要一个专门的字符来标识一个字符串的结束。问题 36:对于各种运算符应该多注意哪些方面?C 语言的特点之一,就是它具有非常丰富的运算符,全面掌握所有运算符是有相当难度的,但也有一定的规律可循

43、,除了应了解运算符的功能处,应该主要注意这几个方面:其一,是运算符所连接的数据类型,不同类型的数据可以参加的运算也不同,比如,|(按位或)运算符,就只能连接整数类数据才有意义;其二,是运算符需要的运算对象的数目;其三,是运算符的优先级,这样最难记忆的一个方面,总的来说,是按单目运算符、算术运算符、关系运算符、逻辑运算符、赋值类运算符、逗号运算符的顺序优先级依次递减。其四,是运算符的结合方向,只有在运算量两边的运算符是同一优先级的运算符时,才考虑运算的优先级,一般而言,大多数单目运算符、赋值类运算符等往往是自右向左结合,其他的一般都自左向右结合。最后,你应该多注意一些特殊的运算符,比如,唯一的一

44、个三目运算符条件运算符,再就是那些充当多个角色的运算符,如:&,既当取地址运算符,也作为按位与运算。问题 37:使用 scanf 函数时应该注意什么问题?scanf 函数是应用非常广泛的一个输入函数,但其使用有一定的难度,如使用不当会带来一些难以料到的错误,主要应该多注意以下几个方面:第一,scanf 函数中的“格式控制”后面就当是变量的地址,而不是变量名,具体说,往往是“&变量名”、指针、指针+数字、数组名+数字等。第二,如果在“格式控制”字符串中除了格式说明以外还有其他字符,则在输入数据时应在相应位置输入与这些字符相同的字符。第三,在用“%c”格式输入字符时,空格字符、回车等都作为有效字符

45、输入 第四,在输入数据时,遇以下情况之一该数据输入结束:遇空格,或回车符或跳格(Tab)按指定宽度输入 遇非法输入,即不符合指定格式的字符,如:scanf(“%d”,&a);输入:345a回车,变量 a得到数值 345。问题 38:如何正确看待 goto 语句在程序中的使用?goto 语句因其不符合结构化程序设计的要求而被大多数程序设计者所不屑,然而事物总是矛盾两方面的联合体,在适当的时候使用 goto 语句比用其它方式可能更好,非但不会破坏程序的可读性,反而使程序更显间洁,所以,从软件工程的角度考虑,应该限制性地使用 goto语句,下面看一个例子:设在闭区间a.b上函数F(X)有唯一的一个零

46、点,用二分法求方程F(X)=0在给定区间内的根。/*程序段 1*/float F0,F1,F(float x),x,x1,x0,a,b;float Fm,Xm;int k;F0=F(a);F1=F(b);if(F0*F1=0)x0=a;x1=b;for(k=1;k=100;k+)Xm=(x0+x1)/2;Fm=F(Xm);if(fabs(Fm)eps|fabs(x1-x0)0)x0=Xm;F0=Fm;else x1=Xm;F1=Fm;finish:printf(“nThe root of this equation is%fn”,Xm);/*程序段 2*/float F0,F1,F(float

47、 x),x,x1,x0,a,b;float Fm,Xm;int k,finished;F0=F(a);F1=F(b);if(F0*F1=0)x0=a;x1=b;k=1;finished=0;while(k=100&finished=0)Xm=(x0+x1)/2;Fm=F(Xm);if(fabs(Fm)eps|fabs(x1-x0)0)x0=Xm;F0=Fm;else x1=Xm;F1=Fm;k+;printf(“nThe root of this equation is%fn”,Xm);程序段 2 中各结构化都符合单入口和单出口的要求,但由于引入了一个变量 finished 作为标志,反倒使程

48、序难以理解了,而这还只是一层循环,如果是多重循环,象程序段 2 的这种程序将更加难懂,如此看来,有时使用 goto 语句,还可以收到意想不到的效果。问题 39:for 语句与 while 语句在实现循环时,哪一个更好?for 语句在很多语言中,都只是一个计数循环语句,即是在已知循环的执行次数的情况下适用,但在 C 语言中,for 语句与 while 语句的功能一样强大,在有些方面显得更有优越性,跟 while 语句相比,for 语句显得更为紧凑,它把与循环控制有关的部分都放在 for 语句的三个表达式中,使得 for 语句更清晰,更容易使用。但对于初学者要掌握 for 语句的执行过程似乎比较困

49、难,主要是难以接受这种形式,既如此,何不去努力适应呢?下面还是把它的执行过程再赘述一次:for 语句的一般形式:for(表达式 1;表达式 2;表达式 3)循环体 其执行过程是:(1)计算表达式 1;(2)计算表达式 2,若其值为真(非 0),则执行循环体,然后执行(3);若为假(值为 0),则结束循环,转至(4);(3)计算表达 3,转(2);(4)执行 for 语句的后续语句。写成与之等价的 while 语句形式是:表达式 1;while(表达式 2)循环体;表达式 3;只要你认真分析 for 语句的执行过程,多加练习,相信你会很快掌握它的使用,并喜欢上它。问题 40:break 语句和

50、continue 语句的作用是什么?什么时候使用它们?break 语句的作用是使流程跳出 switch 结构(参问题 4)或用来从循环体中跳出,即提前结束这两种结构的处理,转而处理它们的后续语句。continue 语句的作用是用在循环体中,提前结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判断。用在循环体,它们两者的区别是前者用于结束整个循环的处理,转而执行循环的后续语句(循环体外部),而后者只是放弃执行它后面的循环体内语句的处理,转而继续判断循环判断语句(循环语句内部)。应该指出,这两者也都不符合结构化程序设计思想,合理安排程序完全可能不使用这两个语句,但与 g

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

当前位置:首页 > 应用文书 > 工作报告

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁