Chapter 3

来源:互联网 发布:淘宝购物车营销不见了 编辑:程序博客网 时间:2024/05/21 15:41

3.6 Loops - Do-While

As we discussed in Chapter 1, the while and for loops test the termination condition at the top. By contrast, the third loop in C, the do-while, tests at the bottom after making each pass through the loop body; the body is always executed at least once.

我们在第1章中曾经讲过,whilefor这两种循环在循环体执行前对终止条件进行测试。与此相反,C语言中的第三种循环——do-while循环则在循环体执行后测试终止条件,这样循环体至少被执行一次。


The syntax of the do is

do

statement

while (expression);

The statement is executed, then expression is evaluated. If it is true, statement is evaluated again, and so on. When the expression becomes false, the loop terminates. Except for the sense of the test, do-while is equivalent to the Pascal repeat-until statement.

在这一结构中,先执行循环体中的语句部分,然后再求表达式的值。如果表达式的值为真,则再次执行语句,依此类推。当表达式的值变为假,则循环终止。除了条件测试的语义不同外,do-while循环与Pascal语言的repeat-until语句等价。


Experience shows that do-while is much less used than while and for. Nonetheless, from time to time it is valuable, as in the following function itoa, which converts a number to a character string (the inverse of atoi). The job is slightly more complicated than might be thought at first, because the easy methods of generating the digits generate them in the wrong order. We have chosen to generate the string backwards, then reverse it.

经验表明,do-while循环比while循环和for循环用得少得多。尽管如此,do-while循环语句有时还是很有用的,下面我们通过函数itoa来说明这一点。itoa函数是atoi

数的逆函数,它把数字转换为字符串。这个工作比最初想像的要复杂一些。如果按照atoi函数中生成数字的方法将数字转换为字符串,则生成的字符串的次序正好是颠倒的,因此,我们首先要生成反序的字符串,然后再把该字符串倒置。


/* itoa: convert n to characters in s */

void itoa(int n, char s[])

{

    int i, sign;

    if ((sign = n) < 0) /* record sign */

    n = -n; /* make n positive */

    i = 0;

    do { /* generate digits in reverse order */

    s[i++] = n % 10 + '0'; /* get next digit */

    } while ((n /= 10) > 0); /* delete it */

    if (sign < 0)

    s[i++] = '-';

    s[i] = '\0';

    reverse(s);

}


The do-while is necessary, or at least convenient, since at least one character must be installed in the array s, even if n is zero. We also used braces around the single statement that makes up the body of the do-while, even though they are unnecessary, so the hasty reader will not mistake the while part for the beginning of a while loop.

这里有必要使用do-while语句,至少使用do-while语句会方便一些,因为即使n的值为0,也至少要把一个字符放到数组s 中。其中的do-while 语句体中只有一条语句,尽管没有必要,但我们仍然用花括号将该语句括起来了,这样做可以避免草率的读者将while部分误认为是另个while循环的开始。



3.7 Break and Continue

It is sometimes convenient to be able to exit from a loop other than by testing at the top or bottom. The break statement provides an early exit from for, while, and do, just as from switch. A break causes the innermost enclosing loop or switch to be exited immediately.

不通过循环头部或尾部的条件测试而跳出循环,有时是很方便的。break 语句可用于从forwhiledo-while等循环中提前退出,就如同从switch语句中提前退出一样。break

语句能使程序从switch语句或最内层循环中立即跳出。


The following function, trim, removes trailing blanks, tabs and newlines from the end of a string, using a break to exit from a loop when the rightmost non-blank, non-tab, non-newline is found.

下面的函数trim用于删除字符串尾部的空格符、制表符与换行符。当发现最右边的字符为非空格符、非制表符、非换行符时,就使用break语句从循环中退出。


/* trim: remove trailing blanks, tabs, newlines */

int trim(char s[])

{

int n;

for (n = strlen(s)-1; n >= 0; n--)

if (s[n] != ' ' && s[n] != '\t' && s[n] != '\n')

break;

s[n+1] = '\0';

return n;

}

strlen returns the length of the string. The for loop starts at the end and scans backwards looking for the first character that is not a blank or tab or newline. The loop is broken when one is found, or when n becomes negative (that is, when the entire string has been scanned). You should verify that this is correct behavior even when the string is empty or contains only white space characters.

下面的函数trim用于删除字符串尾部的空格符、制表符与换行符。当发现最右边的字符为非空格符、非制表符、非换行符时,就使用break语句从循环中退出。


The continue statement is related to break, but less often used; it causes the next iteration of the enclosing for, while, or do loop to begin. In the while and do, this means that the test part is executed immediately; in the for, control passes to the increment step. The continue statement applies only to loops, not to switch. A continue inside a switch inside a loop causes the next loop iteration.

continue 语句与break 语句是相关联的,但它没有break 语句常用。continue 语句用于使forwhile do-while 语句开始下一次循环的执行。在while do-while语句中,continue 语句的执行意味着立即执行测试部分;在for 循环中,则意味着使控制转移到递增循环变量部分。continue 语句只用于循环语句,不用于switch 语句。某个循环包含的switch语句中的continue语句,将导致进入下一次循环。


As an example, this fragment processes only the non-negative elements in the array a; negative values are skipped.

例如,下面这段程序用于处理数组a 中的非负元素。如果某个元素的值为负,则跳过不处理。

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

if (a[i] < 0) /* skip negative elements */

continue;

... /* do positive elements */


The continue statement is often used when the part of the loop that follows is complicated, so that reversing a test and indenting another level would nest the program too deeply.

当循环的后面部分比较复杂时,常常会用到continue 语句。这种情况下,如果不使用continue 语句,则可能需要把测试颠倒过来或者缩进另一层循环,这样做会使程序的嵌套更深。



3.8 Goto and labels

C provides the infinitely-abusable goto statement, and labels to branch to. Formally, the goto statement is never necessary, and in practice it is almost always easy to write code without it. We have not used goto in this book.

C语言提供了可随意滥用的goto语句以及标记跳转位置的标号。从理论上讲,goto语句是没有必要的,实践中不使用goto语句也可以很容易地写出代码。至此,本书中还没有使用goto语句。


Nevertheless, there are a few situations where gotos may find a place. The most common is to abandon processing in some deeply nested structure, such as breaking out of two or more loops at once. The break statement cannot be used directly since it only exits from the innermost loop. Thus:

但是,在某些场合下goto语句还是用得着的。最常见的用法是终止程序在某些深度嵌套的结构中的处理过程,例如一次跳出两层或多层循环。这种情况下使用break语句是不能达到目的的,它只能从最内层循环退出到上一级的循环。下面是使用goto语句的一个例子:

for ( ... )

     for ( ... ) {

...

if (disaster)

goto error;

}

...

error:

/* clean up the mess */

This organization is handy if the error-handling code is non-trivial, and if errors can occur in several places.

在该例子中,如果错误处理代码很重要,并且错误可能出现在多个地方,使用goto语句将会比较方便。


A label has the same form as a variable name, and is followed by a colon. It can be attached to any statement in the same function as the goto. The scope of a label is the entire function.

标号的命名同变量命名的形式相同,标号的后面要紧跟一个冒号。标号可以位于对应的goto语句所在函数的任何语句的前面。标号的作用域是整个函数。


As another example, consider the problem of determining whether two arrays a and b have an element in common. One possibility is

我们来看另外一个例子。考虑判定两个数组a b 中是否具有相同元素的问题。一种可能的解决方法是:


Code involving a goto can always be written without one, though perhaps at the price of some repeated tests or an extra variable. For example, the array search becomes

所有使用了goto语句的程序代码都能改写成不带goto语句的程序,但可能会增加一些额外的重复测试或变量。例如,可将上面判定是否具有相同数组元素的程序段改写成下列形式:



With a few exceptions like those cited here, code that relies on goto statements is generally harder to understand and to maintain than code without gotos. Although we are not dogmatic about the matter, it does seem that goto statements should be used rarely, if at all.

大多数情况下,使用goto语句的程序段比不使用goto语句的程序段要难以理解和维护,少数情况除外,比如我们前面所举的几个例子。尽管该问题并不太严重,但我们还是建议尽可能少地使用goto语句。


原创粉丝点击