C-语言常见问题.docx
《C-语言常见问题.docx》由会员分享,可在线阅读,更多相关《C-语言常见问题.docx(148页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第1章C语言本章主要描述c语言些基本要素。当你开始编写c程序 时,你可能对c语言的些基本问题感到困惑,如c语言所使 用的约定、关键字和术语等。本章将回答这方面你经常会遇到 的些问题。例如,switch语句是最常用的种C语言构件,本章将回答 与它有关的三个常见问题。木章还涉及其它几个问题,如循环、 分支、运算符的优先级和程序块技术。在阅读本章时,请注意 有关switch语句和运算符优先级的些问题,这些问题常常会 使C语言的初学者感到迷惑。1. 1什么是局部程序块(local block)?局部程序块是指对大括号()之间的段C语言程序。 个C函数包含对大括号,这对大括号之间的所有内容都包含 在个局
2、部程序块中。if语句和swich语句也可以包含对大括 号,每对大括号之间的代码也属于个局部程序块。此外,你 完全可以创建你自己的局部程序块,而不使用C函数或基本的 C语句。你可以在局部程序块中说明一些变量,这种变量被称 为局部变量,它们只能在局部程序块的开始部分说明,并且只 在说明它的局部程序块中有效。如果局部变量与局部程序块以 外的变量重名,则前者优先于后者。下面是一个使用局部程序 块的例子:#include void main(void);void main()/ * Begin local block for function main() * /int test_ var = 10;p
3、rintf(Test variable before the if statement: %dn”, test_var);if (test_var5)(/ * Begin local block for if statement * / int test_ var = 5;printf(Test variable within the if statement: %dn, test_var);/ * Begin independent local block (not tied to any function or keyword) * /int test_var = 0;printf(Tes
4、t variable within the independent local block: %dn,test_var)/ * End independent local block * /printf fTest variable after the if statement: %dn test_var);1/*End local block for function main () * /上例产生如下输出结果:Test variable before the if statement: 10Test variable within the if statement: 5Test varia
5、ble within the independent local block:0Test variable after the if statement: 10注意,在这个例子中,每次test_var被定义时,它都要优先 于前面所定义的tesjvar变量。此外还要注意,当if语句的局部 程序块结束时,程序重新进入最初定义的test_var变量的作用范 围,此时test_var的值为!0.请参见:1. 2可以把变量保存在局部程序块中吗?I. 2可以把变量保存在局部程序块中吗?用局部程序块来保存变量是不常见的,你应该尽量避免这样 做,但也有极少数的例外。例如,为了调试程序,你可能要说 明一个全局变
6、量的局部实例,以便在相应的函数体内部进行测 试。为了使程序的某部分变得更易读,你也可能要使用局部 程序块,例如,在接近变量被使用的地方说明个变量有时就 会使程序变得更易读。然而,编写得较好的程序通常不采用这 种方式来说明变量,你应该尽量避免使用局部程序块来保存变 量。请参见:1. I什么是局部程序块?1. 3什么时候用一条switch语句比用多条if语句更好?如果你有两个以上基于同一个数字(numeric)型变量的条件表 达式,那么最好使用一条switch语句。例如,与其使用述代 码:if(x =1)printf (x is equal to one. n);else if (x =2)pri
7、ntf (x is equal to two. nH);else if (x = =3)printf (x is equal to three. n);elseprintf (x is not equal to one, two, or three. n);不如使用下述代码,它更易于阅读和维护:switch (x)breakcase 1: printf (x is equal to one. nH);break;case 2: printf (x is equal to two. nM);breakcase 3: printf (x is equal to three. nH);break;d
8、efault: printf (x is not equal to one, two, or three. nH);break;)注意,使用switch语句的前提是条件表达式必须基于同一个 数字型变量。例如,尽管下述if语句包含两个以上的条件,但 该例不能使用switch语句,因为该例基于字符串比较,而不是 数字比较:char *name=Lupto;if(!stricmp(name ”Isaac)printf(Your name meansLaughter. n);else if(!stricmp(name, Amy)printf( Your name meansBeloved. n);el
9、se if(!stricmp(name, Lloyd)printf(Your name meansMysterious. n);elseprintf(I havent a clue as to what your name means. n);请参见:1. 4 switch语句必须包含default分支吗71. 5 switch语句的最后一个分支可以不要break语句吗?1.4 switch语句必须包含default分支吗?不,但是为了进行错误检査或逻辑检査,还是应该在switch 语句中加入default分支。例如,下述switch语句完全合法: switch (char_code)(cas
10、e tyt:case y: printf ( You answered YES ! n) breakcase N:case n: printf (You answered NO!n);break)但是,如果一个未知字符被传递给这条switch语句,会出现什 么情况呢?这时,程序将没有任何输出。因此,最好还是加入 个default分支,以处理这种情况:default: printf (Unknown response : %dn, char_code); 此外,default分支能给逻辑检查带来很多方便。例如,如果用 switch语句来处理数冃固定的条件,而且认为这些条件之外的 值都属于逻辑错误
11、,那么可以加入个default分支来辨识逻辑 错误。请看下列:void move_cursor (int direction)switch (direction)(case UP: cursor_up()breakcase DOWN: cursor_down()breakcase LEFT: cursor_left ()breakcase RIGHT: cursor_ right () breakdefault:printf (Logic error on line number %ld! n,_ LINE_)break)请参见:1. 3什么时候用一条switch语句比用多条if语句更好?1.
12、 5 Switch语句的最后个分支可以不要break语句吗?1. 5 switch语句的最后一个分支可以不要break语句吗?尽管switch语句的最后一个分支不一定需要break语句,但 最好还是在switch语句的每个分支后面加上break语句,包括 最后个分支。这样做的主要原因是:你的程序很可能要让另个人来维护,他可能要增加一些新的分支,但没有注意到最 后个分支没有break语句,结果使原来的最后个分支受到其 后新増分支的干扰而失效。在毎个分支后面加上break语句将防 止发生这种错误并增强程序的安全性。此外,目前大多数优化 编译程序都会忽略最后一条break语句,所以加入这条语句不会
13、影响程序的性能。请参见:1. 3什么时候用一条switch语句比用多条if语句更好?1. 4 switch语句必须包含default分支吗?1.6除了在for语句中之外,在哪些情况还要使用逗号运算符? 逗号运算符通常用来分隔变量说明、函数参数、表达式以及 for语句中的元素。下例给出了使用逗号的多种方式:#includc #include void main(void);void main ()(/ * Here, the comma operator is used to separate three variable declarations. * /int i, j, k;/ * Not
14、ice how you can use the comma operator to perform multiple initializations on the same line. * /i=0,j=l,k=2;printf(i= %d, j=d, k= %dn”, i, j, k);/ * Here, the comma operator is used to execute three expressionsin one line: assign k to i, increment j, and increment k.The value that i receives is alwa
15、ys the rightmostexpression. * /i=(j+, k+);printf(i=%d,j=%d, k=%dn, i,j, k);/ * Here, the while statement uses the comma operator to assign the value of i as well as test it. * /while (i=(rand() % 100), i !=50)printf(i is %d, trying again. n, i)printf (HnGuess what? i is 50!nH)请注意述语句:i: (j+ k+)这条语句次完
16、成了三个动作,依次为:(1)把k值赋给io这是因为左值(Ivaule)总是等于最右边的参 数,本例的左值等于k。注意,本例的左值不等于k+,因为 k+是个后缀自增表达式,在把k值赋给j之后k会门增。 如果所用的表达式是+k,贝+k的值会被赋给i,因为+k是个前缀自增表达式,k的自增发生在赋值操作之前。(2)j自增.(3)k自増。此外,还要注意看上去有点奇怪的while语句:while (i=(rand() % 100), i !=50)printf(i is %d, trying again. nH);这里,逗号运算符将两个表达式隔开,while语句的每次循环 都将计算这两个表达式的值。逗号左
17、边是第 个表达式,它把 至99之间的一个随机数赋给i!第二个表达式在while语句中更 常见,它是个条件表达式,用来判断i是否不等于50。while 语句每一次循环都要赋予i 个新的随机数,并且检査其值是否 不等于50。最后,i将被随机地赋值为50,而while语句也将结 束循环。请参见:1. 12运算符的优先级总能保证是“自左至右或“自右至左 的顺序吗?1. 13+var和var+有什么区别?1. 7怎样才能知道循环是否提前结束了?循环通常依赖于个或多个变量,你可以在循环外检查这些 变量,以确保循环被正确执行。请看下例:int xchar * cpREQUESTED_BLOCKS/ * At
18、tempt (in vain, I must add. )toallocate 512 10KB blocks in memory. * /for (x = 0; xREQUESTED_ BLOCKS ; x+ )(cpix= (char* ) ma Hoc (10000,1)if(cpx= = (char *) NULL) break)/* Ifx is less than REQUESTED-BLOCKS,the loop has ended prematurely. * /if (xREQUESTED_BLOCKS)printf (Bummer ! My loop ended prema
19、turely ! nH);注意,如果上述循环执行成功,它一定会循环512次。紧接着 循环的if语句用来测试循环次数,从而判断循环是否提前结束。 如果变量x的值小于512,就说明循环出错了。1. 8 goto, longjmp()和 setjmpO之间有什么区别?goto 语句实现程序执行中的近程跳转(localjump),longjmp() 和setjmpO函数实现程序执行中的远程跳转(nonlocaljump,也叫 faijump)。通常你应该避免任何形式的执行中跳转,因为在程序 中使用goto语句或longjmp。函数不是种好的编程习惯。goto语句会跳过程序中的一段代码并转到个预先指定的
20、位 置。为了使用goto语句,你要预先指定个有标号的位置作为 跳转位置,这个位置必须与goto语句在同一个函数内。在不同 的函数之间是无法实现goto跳转的。下面是个使用goto语句 的例子:void bad_programmers_function(void)(int xprintf(Excuse me while I count to 5000. n);while (1)printf( %dn, x)goto all_doneif(x =5000)elsex=x+l;)all_done:prinft(Whew! That wasnt so bad. was it?n);如果不使用got。语
21、句,是例可以编写得更好、下面就是个改 进了实现的例子:void better_function (void)int xprintf(Excuse me while I count to 5000. n);for (x=l; x=5000, x+)printf(M %dn”, x)printf(Whew! That wasnt so bad, was itAn);)前面已经提到,longjmpOft setjmpO函数实现程序执行中的远 程跳转。当你在程序中调用s的mp()时,程序当前状态将被保存 到个jmp_buf类型的结构中。此后,你可以通过调用longjmpO 函数恢复到调用setjmp(
22、)时的程序状态。与goto语句不同, longjmpO和s的mp()函数实现的跳转不一定在同一个函数内。然 而,使用这两个函数有一个很大的缺陷,当程序恢复到它原来 所保存的状态时,它将失去对所有在longjmpO和setjmp()之间 动态分配的内存的控制,也就是说这将浪费所有在longjmpO和 setjmpO之间用malloc()和calloc。分配所得的内存,从而使程序 的效率大大降低。因此,你应该尽量避免使用longjmpO和setjmpO 函数,它们和goto语句样,都是不良编程习惯的表现。面是使用longjmpO函数和setjmpO函数的一个例子:#include #include
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 常见问题
限制150内