C现代方法(第5、6章)笔记

文章目录

  • C现代方法笔记(chapter5&6)
    • 第5章 选择语句
      • 5.1 逻辑表达式
        • 5.1.1 关系运算符
        • 5.1.2 判等运算符
        • 5.1.3 逻辑运算符
      • 5.2 if语句
        • 5.2.1 复合语句
        • 5.2.2 else子句
        • 5.2.3 级联式if语句(else if)
        • 5.2.4 “悬空else”的问题
        • 5.2.5 条件表达式
        • 5.2.6 C89中的布尔值
        • 5.2.7 C99中的布尔值
      • 5.3 switch语句
        • 5.3.1 break语句的作用
      • 问与答
    • 第6章 循环
      • 6.1 while语句
        • 6.1.1 无限循环
      • 6.2 do语句
      • 6.3 for语句
        • 6.3.1 for语句的惯用法
        • 6.3.2 在for语句中省略表达式
        • 6.3.3 C99中的for语句
        • 6.3.4 逗号运算符
      • 6.4 退出循环
        • 6.4.1 break语句
        • 6.4.2 continue语句
        • 6.4.3 goto语句
      • 6.5 空语句
      • 问与答
    • 写在最后

C现代方法笔记(chapter5&6)

第5章 选择语句

5.1 逻辑表达式

包括if语句在内的某些C语句必须测试表达式的值是“真”还是“假”。例如,if语句可能需要检测表达式i < j,若取得真值则说明i小于j。在许多编程语言中,类似i < j这样的表达式都具有特殊的“布尔”类型或“逻辑”类型。这样的类型只有两个值,即假和真。而在C语言中,i < j这样的比较运算会产生整数0(假)1(真)。先记住这一点,下面来看看用于构建逻辑表达式的运算符。

5.1.1 关系运算符

C语言的关系运算符(relational operator)跟数学上的<>运算符相对应,只不过用在C语言的表达式中时产生的结果是0(假)1(真)。例如,表达式10 < 11的值为1,而表达式11 < 10的值为0。

关系运算符可以用于比较整数和浮点数,也允许比较混合类型的操作数。

从优先级上来看,关系运算符的优先级低于算术运算符。

请注意,表达式i < j < k在C语言中是合法的,但是由于<运算符是左结合的,因此表达式等价于(i < k) < k,要判断jik之间,正确的写法应该是i < j && j < k

5.1.2 判等运算符
  • 等于(==)
  • 不等于(!=)

和关系运算符一样,判等运算符也是左结合的,并且产生0(假)1(真)作为结果。然而,判等运算符的优先级低于关系运算符。

5.1.3 逻辑运算符
  • 逻辑非(!)
  • 逻辑与(&&)
  • 逻辑或(||)

逻辑运算符所产生的结果是01。逻辑运算符将任何非零值操作数作为真值来处理,同时将任何零值操作数作为假值来处理。

运算符&&和运算符||都对操作数进行“短路”计算。也就是说,这些运算符首先计算出左操作数的值,然后计算右操作数。如果表达式的值可以仅由左操作数的值推导出来,那么将不计算右操作数的值。

运算符!的优先级和一元正负号的优先级相同,运算符&&和运算符||的优先级低于关系运算符和判等运算符。例如,表达式i < j && k == m等价于表达式(i < j) && (k == m)。运算符!是右结合的,而运算符&&和运算符||都是左结合的。

5.2 if语句

if语句允许程序通过测试表达式的值从两种选项中选择一种。

if语句的最简单格式如下:

if (表达式) 语句

其中,表达式两边的圆括号是必需的,它们是if语句的组成部分。
执行if语句时,先计算圆括号内表达式的值。如果表达式的值非零(C语言把非零值解释为真值),那么接着执行圆括号后边的语句。

5.2.1 复合语句

复合语句由一对花括号,以及花括号内的声明和语句混合而成。可以有多个声明和多条语句,也可以都没有。在后一种情况下,复合语句只有一对花括号,它什么也不做。典型地,通过在一组语句周围放置花括号,可以强制编译器将其作为一条语句来处理。

下面是在if语句内部使用复合语句的形式:

if (line_num == MAX_LINES) {
    line_num = 0;
    page_num++;
}

复合语句也常出现在循环和其他需要多条语句(但C语言的语法要求一条语句)的地方。

5.2.2 else子句

if语句可以有else子句:

if (表达式) 语句 else 语句

如果圆括号内的表达式的值为0,那么就执行else后边的语句。

当在if语句中嵌套if语句时,记得要为语句增加花括号(即使有时并不是必需的),就像在表达式中使用圆括号一样,这两种方法都可以使程序更加容易阅读,同时可以避免出现编译器不能像程序员一样去理解程序的问题。

5.2.3 级联式if语句(else if)

编程时常常需要判定一系列的条件,一旦其中某一个条件为真就立刻停止。“级联式”if语句常常是编写这类系列判定的最好方法。

if (表达式)
  语句
else if (表达式)
  语句
else if (表达式)
  语句
else
  语句

当然,最后两行(else语句)不是总出现的。这种缩进级联式if语句的方
法避免了判定数量过多时过度缩进的问题。此外,这样也向读者证明了这组语句只是一连串的判定。

请记住,级联式if语句不是新的语句类型,它仅仅是普通的if语句,只是碰巧有另外一条if语句作为else子句(而且这条if语句又有另外一条if语句作为它自己的else子句,以此类推)。

5.2.4 “悬空else”的问题

if语句嵌套时,千万要当心著名的“悬空else”的问题。思考下面这个例子:

if (y != 0) 
  if (x != 0) 
    result = x / y; 
else 
  printf("Error: y is equal to 0\n");

上面的else子句究竟属于哪一个if语句呢?缩进格式暗示它属于最外层的if语句。然而,C语言遵循的规则是else子句应该属于离它最近的且还未和其他else匹配的if语句。在此例中,else子句实际上属于最内层的if语句,因此正确的缩进格式应该如下所示:

if (y != 0) 
  if (x != 0) 
    result = x / y; 
  else 
    printf("Error: y is equal to 0\n");

为了使else子句属于外层的if语句,可以把内层的if语句用花括号括起来:

if (y != 0) { 
  if (x != 0) 
    result = x / y; 
} else 
    printf("Error: y is equal to 0\n");

这个示例表明了花括号的作用。如果把花括号用在本节第一个示例的if语句上,那么就不会有这样的问题了。

5.2.5 条件表达式

C语言的if语句允许程序根据条件的值来执行两个操作中的一个。C语言还提供了一种特殊的运算符,这种运算符允许表达式依据条件的值产生两个值中的一个。

条件运算符(conditional operator)由符号?和符号:组成,两个符号必须按如下格式一起使用:

表达式1? 表达式2 : 表达式3

  • 上面的表达式可以是任何类型的表达式,按上述方式组合成的表达式称为条件表达式。条件运算符是C运算符中唯一一个要求3个操作数的运算符。因此,它通常被称为三元运算符

  • 条件表达式表达式1?表达式2:表达式3读作“如果表达式1成立,那么表达式2,否则表达式3”。

  • 条件表达式也普遍用于某些类型的宏定义中。

5.2.6 C89中的布尔值

C89标准中也没有定义布尔类型,但是有几种解决方法。

  • 一种解决方法是先声明一个int型变量,然后将其赋值为01
int flag;
flag = 0;
....
flag = 1;
  • 为了使程序更易于理解,C89的程序员通常使用TRUEFALSE这样的名字定义宏:
#define TRUE 1 
#define FALSE 0 

flag = FALSE; 
... 
flag = TRUE;

为了发扬这一思想,甚至可以定义一个可用作类型的宏:

#define BOOL int
BOOL flag;

在后面的章节中,我们将介绍一些更好的方法,可以使用类型定义( 7.5节)和枚举( 16.5 节)在C89中设置布尔类型。

5.2.7 C99中的布尔值

C99提供了_Bool型,因此在C语言的这一版本中,布尔变量可以声明为
_Bool flag;

_Bool是整数类型(更准确地说是无符号整型),因此_Bool变量实际上就是整型变量;但是和一般的整型不同,_Bool只能赋值为01。一般来说,往_Bool变量中存储非零值会导致变量赋值为1

flag = 5; /* flag is assigned 1 */

除了_Bool类型的定义,C99还提供了一个新的头,这使得操作布尔值更加容易。该头提供了bool宏,用来代表_Bool

#include 
....
bool flag;
flag = false;
....
flag = true;

头使用起来非常方便,因此在后面的程序中需要使用布尔变量时都用到了这个头。

5.3 switch语句

C语言提供了switch语句作为级联式if语句的替代。

if (grade == 4) 
  printf("Excellent"); 
else if (grade == 3) 
  printf("Good"); 
else if (grade == 2) 
  printf("Average"); 
else if (grade == 1) 
  printf("Poor"); 
else if (grade == 0) 
  printf("Failing"); 
else 
  printf("Illegal grade"); 

/

switch (grade)  { 
  case 4:   printf("Excellent"); 
            break; 
  case 3:   printf("Good"); 
            break; 
  case 2:   printf("Average"); 
            break; 
  case 1:   printf("Poor"); 
            break; 
  case 0:   printf("Failing"); 
            break; 
  default:  printf("Illegal grade"); 
            break; 
}

执行上述switch语句时,变量grade的值与43210进行比较。例如,如果值和4相匹配,那么显示信息Excellent,然后break语句( 6.4 节)把控制传递给switch后边的语句。如果grade的值和列出的任何选项都不匹配,那么执行default分支的语句,显示消息
Illegal grade

switch语句往往比级联式if语句更容易阅读。此外,switch语句往往比if语句执行速度快,特别是在有许多情况要判定的时候

switch语句十分复杂,下面逐一看一下它的组成部分。

  • 控制表达式switch后边必须跟着由圆括号括起来的整型表达式。C语言把字符(7.3节)当成整数来处理,因此在switch语句中可以对字符进行判定。但是,这不适用于浮点数和字符串

  • 分支标号。每个分支的开头都有一个标号,格式如下:

    case 常量表达式:

    常量表达式(constant expression)很像普通的表达式,只是不能包含变量和函数调用。因此,5是常量表达式,5 + 10也是常量表达式,但n + 10不是常量表达式(除非n是表示常量的宏)。分支标号中常量表达式的值必须是整数(字符也可以)。

  • 语句。每个分支标号的后边可以跟任意数量的语句,并且不需要用花括号把这些语句括起来。(好好享受这一点,这可是C语言中少数几个不需要花括号的地方。)每组语句的最后一条通常是break语句。

C语言不允许有重复的分支标号,但对分支的顺序没有要求,特别是default分支不一定要放置在最后。

case后边只可以跟随一个常量表达式。但是,多个分支标号可以放置在同一组语句的前面:

switch (grade)  { 
  case 4:  case 3:  case 2:  case l: 
            printf("Passing"); 
            break; 
  case 0:   printf("Failing"); 
            break; 
  default:  printf("Illegal grade"); 
            break; 
} 

switch语句不要求一定有default分支。如果default不存在,而且控制表达式的值和任何一个分支标号都不匹配的话,控制会直接传给switch语句后面的语句。

5.3.1 break语句的作用

需要break语句是由于switch语句实际上是一种“基于计算的跳转”。对控制表达式求值时,控制会跳转到与switch表达式的值相匹配的分支标号处。分支标号只是一个说明switch内部位置的标记。在执行完分支中的最后一条语句后,程序控制“向下跳转”到下一个分支的第一条语句上,忽略下一个分支的分支标号。如果没有break语句(或者其他某种跳转语句),控制将从一个分支继续流向下一个分支。思考下面的switch语句:

switch (grade)  { 
  case 4:   printf("Excellent"); 
  case 3:   printf("Good"); 
  case 2:   printf("Average"); 
  case 1:   printf("Poor"); 
  case 0:   printf("Fai1ing"); 
  default:  printf("Illegal grade"); 
} 

/*
如果grade的值为3,那么显示的消息是  
GoodAveragePoorFailingIllegal grade
*/

问与答

问1:当我用=代替==时,我所用的编译器没有发出警告。是否有办法可以强制编译器注意这类问题?

答:幸运的是,许多编译器可以检测出if条件中=运算符的可疑使用。例如,GCC会在选中-Wparentheses选项或-Wall(所有情况都警告)选项时执行这样的检查。GCC允许程序员通过在if条件外面增加一对圆括号的方式来禁用该警告:

if ((i = j)) ... 

问2:如果iint型变量,ffloat型变量,那么条件表达式(i > 0 ? i: f)是哪一种类型的值?

答:如问题所述,当int型和float型的值混合在一个条件表达式中时,表达式的类型为float型。如果i > 0为真,那么变量i转换为float型后的值就是表达式的值。

问3:为什么_Bool这个名字就不会影响已有的程序呢?

答:C89标准指出,以下划线开头,后跟一个大写字母的名字是保留字,程序员不应该使用。


第6章 循环

循环(loop)是重复执行其他语句(循环体)的一种语句。在C 语言中,每个循环都有一个控制表达式(controlling expression)。每次执行循环体(循环重复一次)时都要对控制表达式求值。如果表达式为真(即值不为零),那么继续执行循环。

C语言提供了3种重复语句,即while语句、do语句和for语句。while循环在循环体执行之前测试控制表达式,do循环在循环体执行之后测试控制表达式,for语句则非常适合那些递增或递减计数变量的循环。

本章最后两节致力于讨论与循环相关的C语言特性。break语句用来跳出循环并把程序控制传递到循环后的下一条语句,continue语句用来跳过本次循环的剩余部分,而goto语句则可以跳到函数内的任何语句上

6.1 while语句

在C语言所有设置循环的方法中,while语句是最简单也是最基本的。while语句的格式如下所示:

while (表达式) 语句

圆括号内的表达式是控制表达式,圆括号后边的语句是循环体

执行while语句时,首先计算控制表达式的值。如果值不为零(即真值),那么执行循环体,接着再次判定表达式。这个过程(先判定控制表达式,再执行循环体)持续进行,直到控制表达式的值变为零才停止。

请注意,虽然循环体必须是单独的一条语句,但这只是个技术问题;如果需要多条语句,那么只要用一对花括号构造成一条复合语句就可以了,比如:

while (i > 0) {
  printf("flsdjfklsdjlkfjklsdj");
  i--;
}
6.1.1 无限循环

如果控制表达式的值始终非零(为真),while语句将无法终止。事实上,C程序员有时故意用非零常量作为控制表达式来构造无限循环

[惯用法] while (1) ...

除非循环体中含有跳出循环控制的语句(breakgotoreturn)或者调用了导致程序终止的函数,否则上述形式的while语句将永远执行下去。

小知识:如何把输出整齐地排成两列?窍门是使用类似%10d这样的转换说明代替%d,并利用了printf函数在指定宽度内输出右对齐的特性。

下面是一个利用循环进行数列求和的例子:

/* Sums a series of numbers */ 

#include  

int main(void) 
{ 
  int n, sum = 0; 

  printf("This program sums a series of integers.\n"); 
  printf("Enter integers (0 to terminate): "); 

  scanf("%d", &n); 
  while (n != 0) { 
    sum += n; 
    scanf("%d", &n); 
  } 
  printf("The sum is: %d\n", sum); 

  return 0; 
} 

/*
This program sums a series of integers. 
Enter integers (0 to terminate): 8 23 71 5 0 
The sum is: 107 
*/

注意,条件n != 0在数被读入后立即进行判断,这样可以尽快终止循环。此外,程序中用到了两个完全一样的scanf函数调用,在使用while循环时往往很难避免这种现象。

6.2 do语句

do语句和while语句关系紧密。事实上,do语句本质上就是while语句,只不过其控制表达式是在每次执行完循环体之后进行判定的。do语句的格式如下所示:

do 语句 while (表达式)

和处理while语句一样,do语句的循环体也必须是一条语句(当然可以用复合语句),并且控制表达式的外面也必须有圆括号。

执行do语句时,先执行循环体,再计算控制表达式的值。如果表达式的值是非零的,那么再次执行循环体,然后再次计算表达式的值。在循环体执行后,若控制表达式的值变为0,则终止do语句的执行。

do语句和while语句往往难以区别。两种语句的区别是,do语句的循环体至少要执行一次,而while语句在控制表达式初始值为0时会完全跳过循环体。

下面是一个利用do循环计算整数的位数的例子:

/* Calculates the number of digits in an integer */ 

#include  

int main(void) 
{ 
  int digits = 0, n; 

  printf("Enter a nonnegative integer: "); 
  scanf("%d", &n); 

  do { 
    n /= 10; 
    digits++; 
  } while (n > 0); 

  printf("The number has %d digit(s).\n", digits); 

  return 0; 
} 

/*
Enter a nonnegative integer: 60 
The number has 2 digit(s). 
*/

6.3 for语句

for语句是C语言循环中最后一种循环,也是功能最强大的一种循环。不要因为for语句表面上的复杂性而灰心;实际上,它是编写许多循环的最佳方法。for语句非常适合应用在使用“计数”变量的循环中,当然它也可以灵活地用于许多其他类型的循环中。格式如下:

for (声明或者表达式1;表达式2;表达式3) 语句

其中表达式1、表达式2 和表达式3全都是表达式。下面是一个例子:

for (i = 10; i > 0; i--) 
  printf("T minus %d and counting\n",i); 

/*
在执行for语句时,变量i先初始化为10,接着判定i是否大于0。因为判定的结果为真,所以打印信息T minus 10 and counting,然后变量i进行自减操作。随后再次对条件i > 0进行判定。循环体总共执行10次,在这一过程中变量i从10变化到1。
*/

for语句和while语句关系紧密。事实上,除了一些极少数的情况以外,for循环总可以用等价的while循环替换:

表达式1;
while (表达式2) {
  语句
  表达式3;
}
6.3.1 for语句的惯用法

对于“向上加”(变量自增)或“向下减”(变量自减)的循环来说,for语句通常是最好的选择。对于向上加或向下减共n次的情况,for语句经常会采用下列形式中的一种。

  • 0向上加到n-1for ( i = 0; i < n; i++) ...
  • 1向上加到nfor ( i = 1; i <= n; i++) ...
  • n-1向下减到0for ( i = n-1; i >= 0; i--) ...
  • n向下减到1for ( i = n; i > 0; i--) ...

模仿上面的书写格式有助于避免C语言初学者常犯的下列错误:

  • 在控制表达式中把>写成<(或者相反)。注意,“向上加”的循环使用运算符<或运算符<=,而“向下减”的循环则依赖于运算符>或运算符>=
  • 在控制表达式中把<<=>>=写成==。控制表达式的值在循环开始时应该为真,以后会变为假以便能终止循环。类似i == n这样的判定没什么意义,因为它的初始值不为真。
  • 编写的控制表达式中把i < n写成i <= n,这会犯“循环次数差一”错误。
6.3.2 在for语句中省略表达式

通常for语句用三个表达式控制循环,但是有一些for循环可能不需要这么多,因此C语言允许省略任意或全部的表达式。

注意,保留第一个表达式和第二个表达式之间的分号。即使省略掉某些表达式,控制表达式也必须始终有两个分号

某些程序员用下列for语句建立无限循环:for (;;) ...

6.3.3 C99中的for语句

在C99中,for语句的第一个表达式可以替换为一个声明,这一特性使得程序员可以声明一个用于循环的变量

for (int i = 0; i < n; i++)

变量i不需要在该语句前进行声明。事实上,如果变量i在之前已经进行了声明,这个语句将创建一个新的i且该值仅用于循环内。

for语句声明的变量不可以在循环外访问(在循环外不可见)。顺便提一下,for语句可以声明多个变量,只要它们类型相同。

for (int i = 0,  j = 0; i < n; i++) 
....
6.3.4 逗号运算符

有些时候,我们可能喜欢编写有两个(或更多个)初始表达式的for语句,或者希望在每次循环时一次对几个变量进行自增操作。使用逗号表达式(comma expression)作为for语句中第一个或第三个表达式可以实现这些想法。

逗号表达式的格式如下所示:

表达式1, 表达式2

这里的表达式1表达式2是两个任意的表达式。逗号表达式的计算要通过两步来实现:

  • 第一步,计算表达式1并且扔掉计算出的值;
  • 第二步,计算表达式2,把这个值作为整个表达式的值。对表达式1的计算应该始终会有副作用;如果没有,那么表达式1就没有了存在的意义。
i = 1, j = 2, k = i + j
/*
因为逗号表达式的左操作数在右操作数之前求值,所以赋值运算i = 1、j = 2 和k = i + j是从左向右进行的。
*/

提供逗号运算符是为了在C语言要求只能有一个表达式的情况下,可以使用两个或多个表达式。换句话说,逗号运算符允许将两个表达式“粘贴”在一起构成一个表达式。(注意它与复合语句的相似之处,后者允许我们把一组语句当作一条语句来使用。)

需要把多个表达式粘在一起的情况不是很多。正如后面的某一章将介绍的那样,某些宏定义( 14.3 节)可以从逗号运算符中受益。除此之外,for语句是唯一可以发现逗号运算符的地方。

6.4 退出循环

然而,有些时候也需要在循环中间设置退出点,甚至可能需要对循环设置多个退出点。break语句可以用于有上述这些需求的循环中。

continue语句会跳过某次迭代的部分内容,但是不会跳出整个循环。goto语句允许程序从一条语句跳转到另一条语句。因为已经有了breakcontinue这样有效的语句,所以很少使用goto语句。

6.4.1 break语句

break语句把程序控制从switch语句中转移出来,还可以用于跳出whiledofor循环。

值得注意的是,break语句把程序控制从包含该语句的最内层whiledoforswitch语句中转移出来。因此,当这些语句出现嵌套时,break语句只能跳出一层嵌套。

while (...) { 
  switch (...)  { 
    ... 
    break; 
    ... 
  } 
}

/*
break语句可以把程序控制从switch语句中转移出来,
但是不能跳出while循环。
*/
6.4.2 continue语句

break语句刚好把程序控制转移到循环体末尾之后,而continue语句刚好把程序控制转移到循环体末尾之前break语句会使程序控制跳出循环,而continue语句会把程序控制留在循环内。break语句和continue语句的另外一个区别是,break语句可以用于switch语句和循环(whiledofor),而continue语句只能用于循环。

6.4.3 goto语句

goto语句在早期编程语言中很常见,但在日常C语言编程中已经很少用到它了。

breakcontinuereturn语句(本质上都是受限制的goto语句)和exit函数( 9.5 节)足以应付在其他编程语言中需要goto语句的大多数情况。

goto语句则可以跳转到函数中任何有标号的语句处。[C99增加了一条限制:goto语句不可以用于绕过变长数组( 8.3 节)的声明。]

  • 标号只是放置在语句开始处的标识符:
    标识符 : 语句
  • 一条语句可以有多个标号。goto语句自身的格式如下:
    goto 标识符

执行语句goto L;,控制会转移到标号L后面的语句上,而且该语句必须和goto语句在同一个函数中

while (...) { 
  switch (...) { 
    ... 
    goto loop_done;     /* break won’t work here */ 
    ... 
  } 
} 
loop_done: ... 
//goto语句对于嵌套循环的退出也是很有用的。

6.5 空语句

语句可以为空,也就是除了末尾处的分号以外什么符号也没有。下面是一个示例:

i = 0; ; j = 1;

这行含有三条语句:一条语句是给i赋值,一条是空语句,还有一条是给j赋值。

空语句主要有一个好处:编写空循环体的循环。(注意空语句单独放置在一行。)

for (d = 2; d < n && n % d != 0; d++) 
  /* empty loop body */; 

C程序员习惯性地把空语句单独放置在一行。否则,有些人阅读程序时可能会搞不清for语句后边的语句是否是其循环体。

请注意!如果不小心在ifwhilefor语句的圆括号后放置分号,则会创建空语句,从而造成ifwhilefor语句提前结束。

问与答

问1

while (i > 0)  
 printf("T minus %d and counting\n", i--);  
为什么不删除“> 0”判定来进一步缩短循环呢?  
while (i)  
 printf("T minus %d and counting\n", i--);  
这种写法的循环会在i 达到0 值时停止,所以它应该和原始版本一样好。

答:新写法确实更加简洁,许多C程序员也这样写循环。但是,它也有缺点。

首先,新循环不像原始版本那样容易阅读。新循环可以清楚地显示出在i达到0值时循环终止,但是不能清楚地表示是向上计数还是向下计数。而在原始的循环中,根据控制表达式i > 0可以推断出这一信息。

其次,如果循环开始执行时i碰巧为负值,那么新循环的行为会不同于原始版本。原始循环会立刻终止,而新循环则不会。

问2:6.3节提到,大多数for循环可以利用标准模式转换成while循环。能给出一个反例吗?

答:当for循环体中含有continue语句时,6.3节给出的while模式将不再有效。

问3:哪个无限循环格式更可取,while(1)还是for(;;)

答:C程序员传统上喜欢for(;;)的高效性。这是因为早期的编译器经常强制程序在每次执行while循环体时测试条件1。但是,对于现代编译器来说,在性能上两种无限循环应该没有差别。

问4:听说程序员应该永不使用continue语句。这种说法对吗?

答:continue语句的确很少使用。尽管如此,continue语句有时还是非常方便的。假设我们编写的循环要读入一些输入数据并测试其有效性,如果有效则以某种方法进行处理。如果有许多有效性测试,或者如果它们都很复杂,那么continue语句就非常有用了。循环将类似于下面这样:

 for(; ;) {  
  读入数据; 
  if(数据的第一条测试失败) 
    continue; 
  if(数据的第二条测试失败) 
    continue;   .   .   . 
  if(数据的最后一条测试失败) 
    continue; 
  处理数据; 
}

问5goto语句有什么不好?

答:goto语句不是天生的魔鬼,只是通常它有更好的替代方式。使用过多goto语句的程序会迅速退化成“垃圾代码”,因为控制可以随意地跳来跳去。垃圾代码是非常难于理解和修改的。

  • 因为goto语句既可以往前跳又可以往后跳,所以使得程序难于阅读。(break语句和continue语句只是往前跳。)含有goto语句的程序经常要求阅读者来回跳转以理解代码的控制流。

  • goto语句使程序难于修改,因为它可能会使某段代码用于多种不同的目的。例如,对于前面有标号的语句,既可以在执行完其前一条语句后到达,也可以通过多条goto语句中的一条到达。

问6:除了说明循环体为空外,空语句还有其他用途吗?

答:非常少。空语句可以放在任何允许放语句的地方,所以有许多潜在的用途。但在实际中,空语句只有一种别的用途,而且极少使用。

问7:除了把空语句单独放置在一行以外,是否还有其他方法可以凸显出空循环体?

答:一些程序员使用虚设的continue语句:

for (d = 2; d < n && n % d != 0; d++) 
  continue;

还有一些人使用空的复合语句:

for (d = 2; d < n && n % d != 0; d++) 
  {}

写在最后

本文是作者阅读《C语言程序设计:现代方法(第2版·修订版)》时所做笔记,日后会持续更新后续章节笔记。欢迎各位大佬批评指正,希望对诸位有所帮助,Thank you very much!

你可能感兴趣的:(C语言,c语言,笔记)