(20)'c++:COMPLETE REFERENCE' 第一部分 第三章(语句) 第二节

时间:2022-10-11 09:00:04

选择语句

      C/C++提供了两种选择语句类型: if语句和switch语句.另外,?操作符在某些特定的情况下可以取代if语句.

if

      if语句的一般格式如下:

if(expression) statement
else statement;

其中,statement可以由单个语句,块语句,或者空语句组成.子语句else是可选了.

      如果expression为true,if后的语句将会被执行,反之,else后的语句将会被执行.总之,if和else后的语句只能有一个被执行.

      在C语言中,expression的值将会是一个数值,这个数值可以是整型,浮点数,字符或者指针.在C++中,expression的值一定是bool类型.浮点数很少被用作条件判断表达式的值,因为这样会明显降低程序的效率.相比之下,整型或者字符型变量的判断时间要短的多.

下面的程序演示了if语句的使用.

/* Magic number program #1. */

#include <stdio.h>
#include <stdlib.h>

int main( void )
{
    int magic;  /* magic number */
    int guess;  /* user's guess */

    magic = rand();  /* generate the magic number */
   
    printf( "Guess the magic number:" );
    scanf( "%d", &guess );

    if( guess == magic )
        printf( "** right **" );

    return 0;
}

这个程序实现简单的猜数字功能.(功能的细节翻译略).rand()函数用来产生随机数.使用rand()函数需要包含头文件

stdlib.h. C++中也可以使用一个新的头文件cstdlib.h.

      下面的程序是上述猜数字游戏的修改版本,演示了else的用法.当用户猜错数字的时候,程序也做出回应.

/* Magic number program #2. */

#include <stdio.h>
#include <stdlib.h>

int main( void )
{
    int magic;  /* magic number */
    int guess;  /* user's guess */

    magic = rand();  /* generate the magic number */
   
    printf( "Guess the magic number:" );
    scanf( "%d", &guess );

    if( guess == magic )
        printf( "** right **" );
    else
        printf( "Wrong!" );

    return 0;
}

嵌套的if语句(Nested ifs)

      嵌套if语句就是说某个if语句块同时又是另一个外层if语句的对象(外层的if语句经过判断表达式后可能执行的语句块).嵌套if语句的使用在编程中非常普遍.else关键字常常和同一个代码块中最近的没有和其它else相组合的if关键字组合.例如:

if( i )
{
    if( j )  statement1;
    if( k )  statement2;   /* This if */
    else     statement3;   /* is associated with this else. */
}
else  statement4;   /* associate with if(i) */

      最后一个else并没有和if(j)组合,因为它们不属于同一个代码块.而花括号中的那个else和if(k)组合是因为它们在同一个代码块中,并且最近.C语言最多允许15层嵌套,而实际上,大部分编译器则支持更多层的嵌套.标准C++允许至少256层嵌套,不过在实际编程中很少有这种必要,而且过多的嵌套会大大降低程序算法的可读性.下面的例子进一步改进了猜数字程序,并且展示了如何使用嵌套if语句.

/* Magic number program #3. */

#include <stdio.h>
#include <stdlib.h>

int main( void )
{
    int magic;  /* magic number */
    int guess;  /* user's guess */

    magic = rand();  /* generate the magic number */
   
    printf( "Guess the magic number:" );
    scanf( "%d", &guess );

    if( guess == magic )
    {
        printf( "** right **" );
        prinft( "%d is the magic number/n", magic );
    }
    else
    {
        printf( "Wrong!" );
        if( guess > magic )
            printf( "too high/n" );
        else
            printf( "too low/n" );
    }

    return 0;
}

if-else-if阶梯

      编程中一种常见的结构是if-else-if呈阶梯状分布.格式如下:

if( expression )  statement1;
else
    if( expression )  statement2;
    else
        if( expression )  statement3;
        .
        .
        .
        else  statementn;

      在这种阶梯状的语句中,程序会从上到下一个个的判断条件表达式并在条件为true的时候执行相应的行为,然后之后的所有语句都被跳过.如果所有的条件表达式都返回false,那么就执行最后一个else对应的操作,如果最后一个else语句不存在,那么就不执行任何操作.

      尽管这种缩进的语句格式是正确的,但是它有可能导致某些语句缩进的过深.所以我们通常采用如下的方式书写这种阶梯状的代码.

if( expression )
    statement1;
else if( expression )
    statement2;
else if( expression )
    statement3;
        .
        .
        .
else
    statementn;

      可以用这种if-else-if阶梯的格式进一步改写猜数字程序.

(程序代码略)

二选一操作符?

      可以用?操作符来替代某些if-else类型的语句.通常格式如下:

if( condition ) expression;
else expression;

这里,if和else的对象语句必须是一个表达式,不能是其它类型的语句.

      ?被称为三元操作符,它有三个操作数.通用格式如下:

Exp1 ? Exp2 : Exp3;

Exp1到3都是表达式.注意不能忘记 : 的使用.

      整个表达式的值是按照这样的规则获得的:先对Exp1求值,如果返回true则Exp2的值就是整个表达式的值,反之,Exp3的值是整个表达式的值.(这个操作符的原理很简单,所以这里省略了一些例子的翻译.)

      ?操作符不仅可以在对象为表达式的时候取代if-else语句,也可以在对象为有返回值的函数时取代if-else语句.在这样的语句中,函数会首先被调用,然后返回一个值.可以把多个函数组成表达式,将表达式作为?操作符的操作数,这样就可以在适合的条件下调用多个函数.看看下面的例子:

#include <stdio.h>

int f1( int n );
int f2( void );

int main( void )
{
    int t;

    printf( "Enter a number:" );
    scanf( "%d", &t );

    /* printf proper message */
    t ? f1(t) + f2() : printf( "zero entered./n" );

    return 0;
}

int f1( int n )
{
    printf( "%d", n );
    return 0;
}

int f2( void )
{
    printf( "entered./n" );
    return 0;
}

      程序运行后,输入0将会显示"zero entered.",如果输入任何非0的数,则函数f1()和f2()都会被调用.需要注意的时,c++编译器会重新编排某些表达式的求值顺序以优化程序的运行,所以有些函数的调用顺序将会是未知的.

      利用?操作符可以把前面的猜数字程序改进如下:

/* Magic number program #3. */

#include <stdio.h>
#include <stdlib.h>

int main( void )
{
    int magic;  /* magic number */
    int guess;  /* user's guess */

    magic = rand();  /* generate the magic number */
   
    printf( "Guess the magic number:" );
    scanf( "%d", &guess );

    if( guess == magic )
    {
        printf( "** right **" );
        prinft( "%d is the magic number/n", magic );
    }
    else
        guess > magic ? printf( "high" ) : printf( "low" );

    return 0;
}

条件表达式

      有些时候C++的新手会有些困惑,任何表达式都可以作为if或者?语句的控制条件.也就是说,不一定非要使用包含逻辑和关系运算符并且只简单的返回true和false的表达式才能作为控制条件.例如,下面的程序读取两个int值并且显示它们的比.程序中使用了一个以第二个变量作为条件的if语句,以防止0被做为除数.

/* Divide the first number by the second. */

#include <stdio.h>

int main( void )
{
    int a, b;

    printf( "Enter two numbers:" );
    scanf( "%d%d", &a, &b );

    if(b) printf( "%d/n", a/b );
    else printf( "Cannot divide by zero./n" );

    return 0;
}

当b为0时,条件表达式的值为false.所以else后的对象被执行.如果把语句写成下面的样子:

if( b != 0 ) printf( "%d/n" );

      这样就显得有些多余,并有可能降低程序的效率,是一种不好的编程风格.在这个语句中,程序还必须把b与0进行一次匹配.

switch

      C/C++定义了内建的多分支选择关键字:switch.在switch语句中,会挨个把表达式与一列整型或者字符常量匹配,直到找到一个相同的.这时,对应于那个常量的语句将被执行.通常格式如下:

switch( expression ){
    case constant1:
        statement sequence
        break;
    case constant2:
        statement sequence
        break;
    case constant1:
        statement sequence
        break;
    case constant3:
        statement sequence
        break;
    .
    .
    .
    default
        statement sequence
}

      表达式expression的值必须是整型或者字符,浮点型等其它类型的表达式不允许使用.expression表达式的值将会按照顺序一个个的与case语句中的常量匹配,当匹配成功时,这个常量对应的语句序列将会被执行,直到遇到break或者整个switch语句结束.如果没有对应的常量匹配成功,那么将会执行default后的语句序列.default语句时可选的,如果不存在该语句,当所有匹配都失败之后,switch语句会退出,不执行任何操作.

      在C语言中,switch语句可以最多包含257个switch语句.标准C++则建议编译器允许switch语句包含16384个case.在实际应用中,为了提高效率,我们会尽可能的减少case语句的数量.尽管含有case关键字的语句称为标号语句,但是它们不能脱离switch之外而独立存在.

      break是C/C++中的跳转关键字之一.它除了应用与switch语句之外,还可以用在循环语句中.当switch语句中出现break时,程序将会跳转到整个switch语句后的第一个语句开始执行.

      关于switch语句,以下有三点重要的知识必须掌握:

      switch和if两种语句有很大不同,switch语句只能用是否相等来作为判断条件,而if语句可以把任何类型的表达式做为判断条件.

      同一个switch语句中并列的所有case的值不能重复,不过switch语句中如果嵌套了新的switch语句,那么它们的case之间不在同一个级别,不是并列关系,可以重复同一个值.

      如果在case语句中使用了字符常量,它们会自动被转换为整型.

      switch语句常被用来处理键盘消息,如菜单的选择.下面的示例函数menu()将会显示一个拼写检查程序的菜单并且把菜单选项与相应的操作程序连接起来.

void menu( void )
{
    char ch;

    printf( "1. Check Spelling/n" );
    printf( "2. Correct Spelling Errors/n" );
    printf( "3. Display Spelling Errors/n" );
    printf("      Enter your choice: " );

    ch = getchar();  /* read the selection from the keyboard */

    switch(ch){
        case '1':
            check_spelling();
            break;
        case '2':
            correct_errors();
            break;
        case '3':
            display_errors();
            break;
        default:
            printf( "No option selected." );
    }
}

      从技术角度来说,switch语句中的break都是可选的.它们结束了case语句中常量所对应的语句序列.如果break被省略,那么程序在执行完case后的语句序列之后,会继续执行下一个case语句序列,直到遇到break或者整个switch语句结束.下面的例子就是如何利用switch语句的这种特性来简化一个外设输入处理程序:

/* Process a value */
void inp_handler( int i )
{
    int flag;

    flag = -1;

    switch(i){
        case 1:  /* These cases have */
        case 2:  /* common */
        case 3:  /* statement sequences. */
            flag = 0;
            break;
        case 4:
            flag = 1;
        case 5:
            error( flag );
            break;
        default:
            process(i);
    }
}

      这个例子介绍了switch使用中的两个知识点:第一,case语句不一定要有对应的语句序列.如果匹配成功的case对应的语句序列不存在,程序自动执行下一个case语句序列直到break或者整个语句结束.第二,在没有遇到break的时候,程序会顺序执行所有的case语句序列.例如,如果i等于4,flag将会被置为1,然后又会调用error(flag),然后遇到break退出.如果i等于5,程序会直接调用error(flag),这是flag参数的数值为-1.

      实际上,如果整个switch语句中没有break,那么程序将会执行第一个匹配的case后的所有语句序列.这种特性如果好好利用可以编写出更加高效的程序.

嵌套switch语句

      可以把switch语句作为外层switch语句中的,某个case的执行语句序列.两层switch语句的case可以有相同的常量,这并不会产生冲突.例如,下面的语句就时合法的:

switch(x){
    case 1:
        switch(y){
            case 0:
                printf( "Divide by zero error./n" );
                break;
            case 1:
                process( x, y );
        }
        break;
    case 2:
    .
    .
    .