<返回更多

C语言之妙:scanf 的双重作用

2020-07-21    
加入收藏
C语言之妙:scanf 的双重作用

 

我们尝试用scanf做累加运算:

/* summing.c -- sums integers entered interactively */
#include <stdio.h>
int main(void)
{
    long num;
    long sum = 0L;      /* initialize sum to zero   */
    int status;

    printf("Please enter an integer to be summed ");
    printf("(q to quit): ");
    status = scanf("%ld", &num);
    while (status == 1) /* == means "is equal to"   */
    {
        sum = sum + num;
        printf("Please enter next integer (q to quit): ");
        status = scanf("%ld", &num);
    }
    printf("nThose integers sum to %ld.n", sum);

    return 0;
}

该程序使用long类型以存储更大的整数。尽管C编译器会把0自动转换为合适的类型,但是为了保持程序的一致性,我们把sum初始化为0L(long类型的0),而不是0(int类型的0)。该程序的运行示例如下:

Please enter an integer to be summed (q to quit): 44

Please enter next integer (q to quit): 33

Please enter next integer (q to quit): 88

Please enter next integer (q to quit): 121

Please enter next integer (q to quit): q

Those integers sum to 286.

分布解析

先看while循环,该循环的测试条件是如下表达式:

status == 1

运算符是C的相等运算符(equality-operator),该表达式判断status是否等于1。不要把status == 1 与 status = 1混淆,后者是把1赋给status。根据测试条件status == 1,只要status等于1,循环就会重复。每次循环,num的当前值都被加到sum上,这样sum的值始终是当前整数之和。当status的值不为1时,循环结束。然后程序打印sum的最终值。

要让程序正常运行,每次循环都要获取num的一个新值,并重置status。程序利用scanf()的两个不同的特性来完成。首先,使用scanf()读取num的一个新值;然后,检查scanf()的返回值判断是否成功获取值。第4章中介绍过,scanf()返回成功读取项的数量。如果scanf()成功读取一个整数,就把该数存入num并返回1,随后返回值将被赋给status(注意,用户输入的值存储在num中,不是status中)。

这样做同时更新了num和status的值,while循环进入下一次迭代。如果用户输入的不是数字(如,q),scanf()会读取失败并返回0。此时,status的值就是0,循环结束。因为输入的字符q不是数字,所以它会被放回输入队列中(实际上,不仅仅是q,任何非数值的数据都会导致循环终止,但是提示用户输入q退出程序比提示用户输入一个非数字字符要简单)。

如果scanf()在转换值之前出了问题(例如,检测到文件结尾或遇到硬件问题),会返回一个特殊值EOF(其值通常被定义为-1)。这个值也会引起循环终止。如何告诉循环何时停止?该程序利用scanf()的双重特性避免了在循环中交互输入时的这个棘手的问题。例如,假设scanf()没有返回值,那么每次循环只会改变num的值。虽然可以使用num的值来结束循环,比如把num > 0(num大于0)或num != 0(num不等于0)作为测试条件,但是这样用户就不能输入某些值,如-3或0。也可以在循环中添加代码,例如每次循环时询问用户“是否继续循环?<y/n>”,然后判断用户是否输入y。这个方法有些笨拙,而且还减慢了输入的速度。使用scanf()的返回值,轻松地避免了这些问题。

伪码

现在,我们来看看该程序的结构。总结如下:

initialize sum to 0
prompt user
read input
while the input is an integer,
     add the input to sum,
     prompt user,
     then read next input
after input completes, print sum

顺带一提,这叫作伪代码(pseudocode),是一种用简单的句子表示程序思路的方法,它与计算机语言的形式相对应。伪代码有助于设计程序的逻辑。确定程序的逻辑无误之后,再把伪代码翻译成实际的编程代码。使用伪代码的好处之一是,可以把注意力集中在程序的组织和逻辑上,不用在设计程序时还要分心如何用编程语言来表达自己的想法。例如,可以用缩进来代表一块代码,不用考虑C的语法要用花括号把这部分代码括起来。

总之,因为while循环是入口条件循环,程序在进入循环体之前必须获取输入的数据并检查status的值,所以在while前面要有一个scanf()。要让循环继续执行,在循环内需要一个读取数据的语句,这样程序才能获取下一个status的值,所以在while循环末尾还要有一个scanf(),它为下一次迭代做好了准备。可以把下面的伪代码作为while循环的标准格式:

get first value to be tested
while the test is successful
     process value
     get next value

C 风格读取循环

根据伪代码的设计思路,程序清单6.1可以用Pascal、BASIC或FORTRAN来编写。但是C更为简洁,下面的代码:

status = scanf("%ld", &num);
while (status == 1)
{
        /* loop actions */
        status = scanf("%ld", &num);
}

// can be replaced by the following:

while (scanf("%ld", &num) == 1)
{
        /* loop actions */
}

第二种形式同时使用scanf()的两种不同的特性。

首先,如果函数调用成功,scanf()会把一个值存入num。

然后,利用scanf()的返回值(0或1,不是num的值)控制while循环。

因为每次迭代都会判断循环的条件,所以每次迭代都要调用scanf()读取新的num值来做判断。换句话说,C的语法特性让你可以用下面的精简版本替换标准版本。

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>