C Primer Plus 第7章 C控制语句:分支和跳转 7.2 if语句中添加 else 关键字

夙愿已清 提交于 2020-03-02 19:06:17

if else 语句的通用形式为:

if (expression)

    statement1

else

    statement2

如果expression为真(非零),就执行statement1;如果expression为假或零,则执行跟在else后的那一条语句(statement2)。

如果希望在if和else之间有多条语句,必须使用花括号创建一个代码块。

if语句使您能够选择是否执行某个动作。if else语句使您可以在两个动作之间进行选择。

7.2.1 另一个例子:介绍getchar()和putchar()

现在我们将接触专门 为面向字符I/O而设计的一对C函数:getchar()和putchar()。

getchar()函数没有参数,它返回来自输入设备的下一个字符。

ch=getchar();与scanf("%c",&ch);有同样的效果。

putchar()函数打印它的参数。例如,下面的语句将先前赋值给ch的值作为字符打印出来:

putchar(ch);

该语句与printf("%c",ch);有同样的效果。

因为这些函数仅仅处理字符,所以它们比更通用的scanf()和printf()函数更快而且更简洁。同样,注意到它们不需要格式说明符,因为它们只对字符 起作用。

这两个函数通常都是在stdio.h文件中定义的。

下面的示例将说明这些函数是如何工作的,“如果字符 是空格,打印之;否则,打印它们在ASCII序列中的下一个字符”。

程序清单7.2  cypher1.c 程序

/*cypher1.c --改变输入,只保留其中的空格*/
#include  
#define SPACE ' '  /*SPACE相当于“引号-空格-引号”*/
int main(void)
{
    char ch;

    ch=getchar();  /*读入一个字符*/
    while(ch!='\n') /*当一行未结束时*/
    { 
        if(ch==SPACE)
          putchar(ch);
        else
          putchar(ch+1);
        ch=getchar();
    }
    putchar(ch);   /*换行打印字符*/
    return 0;
}
/*下面是一个运行示例:
CALL ME HAL.
DBMM NF IBM/
*/

C灵活的语法使您可以通过将读取和判断合并为单个表达来仿效程序清单7.1。就是说,您可以把这种形式的循环:

ch=getchar();

while(ch!='\n')

{

    ...

    ch=getchar();

}

替换为下面的形式:

while((ch=getchar())!='\n')

{

    ....

}

关键的一行是while( (ch=getchar()) != '\n' )

这体现了c的编程风格:将两个动作合并为一个表达式。

圆括号是必须的,因为!=的优先级要比=的高。

putchar(ch+1)再次证明了字符实际上是作为整数存储的

7.2.2 ctype.h系列字符函数

ctype.h头文件包含了一些可以用来分析字符的函数的原型。这些函数接受一个字符作为参数,如果该字符 属于某特定的种类则返回非零值(真),否则返回零(假)。

例如,如果isalpha()函数的参数是一个字母,则它返回一个非零值。程序清单7.3通过使用该函数扩展了程序清单7.2。

程序清单7.3 cypher2.c

#include 
#include 
int main (void)
{
    char ch;

    while((ch=getchar())!='\n')
    {
        if(isalpha(ch))    //如果是一个字母
            putchar(ch+1); //则改变它
        else               //否则
            putchar(ch);   //原样打印它
    }
    putchar(ch);           //打印换行符
    return 0;
}

表7.1 ctype.h的字符判断函数

函数名 为如下参数时,返回值为真
isalnum() 字母或数字
isalpha() 字母
isblank() 一个标准的空白字符(空格、水平制表符、或换行)
iscntrl() 控制符,例如ctrl+B
isdigit() 阿拉伯数字
isgraph() 除空格外的所有可打印字符
islower() 小写字母
isprint() 可打印字符
ispunct() 标点符号(除空格和字母数字外的可打印字符)
isspace() 空白字符
isupper() 大写字母
isxdigit() 十六进制数字字符

表7.2 ctype.h的字符映射函数

函数名 动作
tolower() 返回参数的小写字符
toupper() 返回参数的大写字符

7.2.3  多重选择else if

日常生活中,经常会给我们提供两个以上的选择。

程序清单7.4  electric.c

/*electric.c --计算用电帐目*/
#include 
#define RATE1 0.12589  /*第1 个360KWH的费率*/
#define RATE2 0.17901  /*下一个320KWH的费率*/
#define RATE3 0.20971  /*超过680KWH的费率*/
#define BREAK1 360.0   /*费率的第一个分界点*/
#define BREAK2 680.0   /*费率的第二个分界点*/
#define BASE1 (RATE1*BREAK1) /*用电360KWH的费用*/
#define BASE2 (BASE1+(RATE2*(BREAK2-BREAK1)))  /*用电680KWH的费用*/
int main (void)
{
    double kwh;   /*用电的千瓦小时数*/
    double bill;  /*费用*/

    printf("Please enter the kwh used.\n");
    scanf("%lf",&kwh);  /*%lf是double类型的说明符*/
    if(kwh<=BREAK1)  
        bill = RATE1 * kwh;
    else if (kwh <= BREAK2)  /*用电量在360-680kwh之间*/
        bill = BASE1 + (RATE2 * (kwh-BREAK1));  
    else               /*用电超出680kwh时*/
        bill = BASE2 + (RATE3 * (kwh-BREAK2));
    printf("The charge for %.1f kwh is $1.2f.\n",kwh,bill);
    return 0;
}
    

程序清单7.4用符号常量表示费率,以便这些常量可以很方便的被放置在一起。该清单也用 符号表示了费率的分界点。BASE1和BASE2根据费率和分界点来表示。这样,如果费率或分界点改变了,它们也会自动的更新。您可能回想起预处理器是不做计算的,程序中BASE1出现的地方将使用0.12589*360.0代替。不用担心,编译器会求得该表达式的数值(45.3204)以便最终的程序代码使用45.3204而不是一个计算表达式。

程序的流程简单明了。应该特别注意的是仅当KWH大于360时程序才到达第一个else。所以,像程序注释的那样,else if 行实际上相当于要求kwh在360和680之间。同样仅当kwh超过680才能到达最后一个else。

说到编译器的嵌套限制,C99标准要求编译器最少支持127层嵌套。

7.2.4  把else 与 if 配对

当有众多的if和else的时候 ,计算机是怎样判断哪个if对应哪个else的?

规则是如果没有花括号指明,else与和它最接近的一个if相匹配。

7.2.5   多层嵌套的if

前面所看到的if...else if...else序列是嵌套if的一种形式,这是从一系列的二选一中进行选择的。当进行了特定的选择后又导致了额外的选择时将使用另一种嵌套if。

我们试着用这种形式的嵌套if来解决下面的问题:给定一个整数,显示所有能整除它的约数;如果没有约数,则报告该数是个素数。

首先,对程序进行整体设计,为了方便,程序需要用一个循环来使您能输入被测试的数。

下一步,需要 计划怎么来找到除数。或许最显而易见的方法是这样的:

for(dir=2;div

    if(num%div==0)

        printf("%d is divisible by %d\n",num,div);

该循环检查界于2到num之间的所有数,看它们是否可以整除num。不幸的是这样浪费了计算机的时间。我们可以做的更好。例如,考虑搜索144的约数。可以发现144%2为0,这意味着144能被2整除。如果明确的拿144除以2,可以得到72,这也是一个约数,因此一次成功的num%div测试可以得到两个约数而不是一个。然而,真正的性能指标在于循环测试界限的改变。

为了弄清这是怎么工作的,看一下循环中所得到的成对的约数:2和72、3和48、4和36、6和24、8和18、9和16、12和12、16和9、18和8等。哦,在得到12和12这对约数后,又开始得到与已找到的相同的约数(以相反的次序)。无须循环到143,在达到12后就可以停止。这就节省 了大量的循环周期。

归纳以后,可以确定必须测试的数只要到num的平方根就可以了,而不必到num。对于像9这样的数,这并不会节省很多时间,但对于像10000这样的数,差别就很大了。然而,我们不必在程序中计算平方根,而是像下面这样描述判断条件:

for (div=2;(div*div)<=num;div++)

    if(num%div==0)

    printf("%d is divisible by %d and %d.\n",num,div,num / div);

如果num为144,循环运行到div=12终止。如果Num为145,循环运行到div=13终止。

我们还需要提出两个问题,然后才能准备开始编程。第一,如果测试的数是一个完全平方数怎么办?报告144可被12和12整除显然有些愚蠢,但可以用嵌套if语句来判断div是否等于num / div。如果是,程序将只打印一个约数,而不是两个。

for (div = 2;(div*div)<=num;div++)

{

    if(num % div == 0)

    {

        if(div*div!=num)

            printf( "%d is divisible by %d\n",num,div);

                else

                         printf("%d is divisible by %d.\n",num,div);

        }

}

第二,怎么知道一个数是素数呢?如果一个数是素数,程序永远也进不了if语句。为了解决这个问题,可以在循环外设置一个变量为某一值,比方说1,在if语句中将这个变更重设为0.那么循环完成后,检查该变量是否仍然是1.如果是,则从来没有进入过if语句,这个数是素数。

这样的变量通常称为标志(flag)。

传统上,C习惯了用Into类型作为标志,但是新型的_Bool型变量极佳地符合了这种需求。而且通过使用stdbool.h头文件,可以用bool代替_Bool表示这种类型,并用标识符true和false代替1和0.

程序清单 7.5 divisors.c

//divisors.c --使用嵌套if显示一个数的约数
#include <stdio.h>
#include <stdbool.h>
int main(void)
{
    unsigned long num;          //要检查的数
    unsigned long div;          //可能的约数
    bool isprime;               //素数的标志

    printf("Please enter an integer for analysis:");
    printf("Enter q to quit.\n");
    while(scanf("%lu",&num)==1)
    {
        for(div=2,isprime=true;(div*div)<=num;div++)
        {
            if(num % div == 0)
            {
                if((div*div)!=num)
                    printf("%lu is divisible by %lu and %lu.\n",num,div,num / div );
                else
                    printf("%lu is divisible by %lu.\n",num,div);
                isprime=false;     //不是一个素数
            }
        }
        if(isprime)
            printf("%lu is prime.\n",num);
        printf("Please enter another integer for analysis;");
        printf("Enter q to quit.\n");
    }
    printf("Bye.\n");
    return 0;
}

这个程序将会把1判断为素数,而实际上1不是素数。下一部分将要介绍的逻辑运算符将使你能够把1排除在外。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!