/ guess.c -- an inefficient and faulty number-guesser /#include <stdio.h>int main(void){ int guess = 1; printf("Pick an integer from 1 to 100. I will try to guess "); printf("it.\nRespond with a y if my guess is right and with"); printf("\nan n if it is wrong.\n"); printf("Uh...is your number %d?\n", guess); while (getchar() != 'y') / get response, compare to y / printf("Well, then, is it %d?\n", ++guess); printf("I knew I could do it!\n"); return 0;}

下面是程序的运行示例:

Pick an integer from 1 to 100. I will try to guess it.

Respond with a y if my guess is right and with

phprowcolforC说话中若何getchar若何处置n换行的问题 Ruby

an n if it is wrong.

Uh...is your number 1?

n

Well, then, is it 2?

Well, then, is it 3?

n

Well, then, is it 4?

Well, then, is it 5?

y

I knew I could do it!

撇开这个程序糟糕的算法不谈,我们先选择一个数字。
把稳,每次输入n时,程序打印了两条。
这是由于程序读取n作为用户否定了数字1,然后还读取了一个换行符作为用户否定了数字2。

一种办理方案是,利用while循环丢弃输入行末了剩余的内容,包括换行符。
这种方法的优点是,能把no和no-way这样的相应视为大略的n。
而第一个版本会把no当作两个相应。
下面用循环改动这个问题:

while (getchar() != 'y') / get response, compare to y /{ printf("Well, then, is it %d?n", ++guess); while (getchar() != '\n') continue; / skip rest of input line /}

下面是程序的运行示例:

Pick an integer fromxs 1 to 100. I will try to guess it.Respond with a y if my guess is right and withan n if it is wrong.Uh...is your number 1?nWell, then, is it 2?noWell, then, is it 3?no sirWell, then, is it 4?forget itWell, then, is it 5?yI knew I could do it

这的确是办理了换行符的问题。
但是,该程序还是会把f视为n。
我们用if语句筛选其他相应。
首先,添加一个char类型的变量存储相应:

: char response;

修正后的循环如下:

现在,程序的运行示例如下:

while ((response = getchar()) != 'y') / get response /{ if (response == 'n') printf("Well, then, is it %d?n", ++guess); else printf("Sorry, I understand only y or n.n"); while (getchar() != 'n') continue; / skip rest of input line /}

在编写交互式程序时,该当事先预见到用户可能会输入缺点,然后设计程序处理用户的缺点输入。
在用户出错时关照用户再次输入。
当然,无论你的提示写得多么清楚,总会有人误解,然后抱怨这个程序设计得多么糟糕。

2 稠浊数值和字符输入

假设程序哀求用getchar()处理字符输入,用scanf()处理数值输入,这两个函数都能很好地完成任务,但是不能把它们混用。
由于getchar()读取每个字符,包括空格、制表符和换行符;而scanf()在读取数字时则会跳过空格、制表符和换行符。

我们通过程序清单8.5来阐明这种情形导致的问题。
该程序读入一个字符和两个数字,然后根据输入的两个数字指定的行数和列数打印该字符。

/ showchar1.c -- program with a BIG I/O problem /#include <stdio.h>void display(char cr, int lines, int width);int main(void){ int ch; / character to be printed / int rows, cols; / number of rows and columns / printf("Enter a character and two integers:n"); while ((ch = getchar()) != 'n') { scanf("%d %d", &rows, &cols); display(ch, rows, cols); printf("Enter another character and two integers;\n"); printf("Enter a newline to quit.\n"); } printf("Bye.n"); return 0;}void display(char cr, int lines, int width){ int row, col; for (row = 1; row <= lines; row++) { for (col = 1; col <= width; col++) putchar(cr); putchar('n'); / end line and start a new one / }}

把稳,该程序以int类型读取字符(这样做可以检测EOF),但是却以char类型把字符通报给display()函数。
由于char比int小,一些编译器会给出类型转换的警告。
可以忽略这些警告,或者用下面的逼迫类型转换肃清警告:

display(char(ch), rows, cols);

在该程序中,main()卖力获取数据,display()函数卖力打印数据。
下面是该程序的一个运行示例,看看有什么问题:

Enter a character and two integers:

c 2 3

ccc

ccc

Enter another character and two integers;

Enter a newline to quit.

Bye.

该程序开始时运行良好。
你输入c 2 3,程序打印c字符2行3列。
然后,程序提示输入第2组数据,还没等你输入数据程序就退出了!
这是什么情形?又是换行符在捣乱,这次是输入行中紧跟在3后面的换行符。
scanf()函数把这个换行符留在输入行列步队中。
和scanf()不同,getchar()不会跳过换行符,以是在进入下一轮迭代时,你还没来得及输入字符,它就读取了换行符,然后将其赋给ch。
而ch是换行符正式终止循环的条件。

要办理这个问题,程序要跳过一轮输入结束与下一轮输入开始之间的所有换行符或空格。
其余,如果该程序不在getchar()测试时,而在scanf()阶段终止程序会更好。
修正后的版本如下。

/ showchar2.c -- prints characters in rows and columns /#include <stdio.h>void display(char cr, int lines, int width);int main(void){ int ch; / character to be printed / int rows, cols; / number of rows and columns / printf("Enter a character and two integers:n"); while ((ch = getchar()) != 'n') { if (scanf("%d %d",&rows, &cols) != 2) break; display(ch, rows, cols); while (getchar() != 'n') continue; printf("Enter another character and two integers;n"); printf("Enter a newline to quit.n"); } printf("Bye.n"); return 0;}void display(char cr, int lines, int width){ int row, col; for (row = 1; row <= lines; row++) { for (col = 1; col <= width; col++) putchar(cr); putchar('n'); / end line and start a new one / }}

while循环实现了丢弃scanf()输入后面所有字符(包括换行符)的功能,为循环的下一轮读取做好了准备。
该程序的运行示例如下:

Enter a character and two integers:c 1 2ccEnter another character and two integers;Enter a newline to quit.! 3 6!!!!!!!!!!!!!!!!!!Enter another character and two integers;Enter a newline to quit.Bye.

在if语句中利用一个break语句,可以在scanf()的返回值不即是2时终止程序,即如果一个或两个输入值不是整数或者碰着文件结尾就终止程序。

n