11

以下代码在我编译后立即给出了奇怪的 o/p。

main() {
    char name[3];
    float price[3];
    int pages[3], i;

    printf ( "\nEnter names, prices and no. of pages of 3 books\n" ) ;

    for ( i = 0 ; i <= 2 ; i++ )
        scanf ("%c %f %d", &name[i], &price[i], &pages[i] );

    printf ( "\nAnd this is what you entered\n" ) ;

    for ( i = 0 ; i <= 2 ; i++ )
        printf ( "%c %f %d\n", name[i], price[i], pages[i] );
}

但是如果我们在 %c 之前的 scanf 语句中给出空格,它会给出正确的 o/p。

谁能解释一下为什么会这样?

更新:-

如果我提供这样的输入 -

F
123.45
56
J
134
67
K
145
98

那么我的问题是为什么我们不在 %f 之前给空间,在 %d 之前给空间?为什么我们只需要在 %c 之前给空间?

4

2 回答 2

17

在格式字符串中添加空格可以scanf使用每次按 时发生的输入中的换行符return。没有空格,name[i]将接收 char '\n',而真正的char 会被%f.

所以,说你的输入是

a 1.0 2
b 3.0 4
c 5.0 6

程序看起来更像这样:

a 1.0 2\nb 3.0 4\nc 5.0 6\n\377

也就是说,换行符是文件中的实际字符(这里的 \377 表示“文件结尾”)。

第一个scanf似乎工作正常,消耗一个字符、一个浮点数和一个整数。但它留下这样的输入:

\nb 3.0 4\nc 5.0 6\n\377

所以第二个scanf将读取'\n'它的 %c,除非你先摆脱它。

将空格添加到格式字符串会指示 scanf 丢弃任何空白字符(任何空格' '、制表符'\t'或换行符'\n')。

指令是以下之一:

  • 一系列空白字符(空格、制表符、换行符等;参见 isspace(3))。该指令匹配输入中任意数量的空白,包括无空白。

  • ...

来自http://linux.die.net/man/3/scanf


每当您在循环中使用scanfwith时,都会出现此类问题。%c因为,假设输入自由,换行符可以出现在任何地方。因此,通常尝试通过使用两层方法来避免整个问题。您将输入读入缓冲区(使用fgets);砍掉愚蠢的换行符;然后使用sscanf而不是scanf从缓冲区(字符串)中读取,而不是直接从文件中读取。

于 2013-06-13T04:25:38.307 回答
6

使用 %c 输入错误

考虑以下代码片段:

int main( ){
int x;
char y;
scanf("%d", &x);
scanf("%c", &y);
printf("%d %c", x, y);
}

行为:
当您运行上述程序时,第一个 scanf 被调用,它将等待您输入一个十进制数。假设您输入 12(即 ASCII '1' 和 ASCII '2')。然后按“enter”键表示输入结束。接下来程序将执行第二个scanf,但您会注意到程序不会等待您输入字符,而是直接输出12,后跟'\n'。



解释:
为什么会这样?让我们逐步看一下程序的行为。最初缓冲区中没有任何内容。当第一个 scanf() 被调用时,它没有要读取的内容,所以它等待。它一直等到您输入 1,2,然后“输入”。现在缓冲区中的内容是字符 1、字符 2 和字符 '\n'。请记住,'\n' 表示输入结束,一旦输入了所有字段,但它也作为 ASCII 字符存储在缓冲区中。此时 scanf 将从缓冲区中读取最大的十进制输入并将其转换为整数。在此示例中,它找到字符串“12”并将其转换为十进制值 12 并将其放入 x 中。然后scanf将控制权返回给主函数并返回值1,能够成功转换一个条目。在我们的示例中,我们没有在变量中捕获 scanf 的返回值。对于健壮的代码,检查 scanf() 的返回值以确保用户输入正确的数据很重要。



现在留在缓冲区中的是'\n'。接下来,调用第二个 scanf 并期待一个字符。由于缓冲区中已经有 '\n' 字符,scanf 看到它,从缓冲区中取出它,并将其放入 y 中。这就是为什么当你之后执行 printf 时,12 和“enter”会打印到屏幕上。



解决方案:
故事的寓意是,enter 是一个和其他字符一样的字符,并且被输入到缓冲区,并像任何其他 ASCII 字符一样被 %c 从缓冲区消耗。要解决此问题,请尝试改用此代码:


int main( ){
int x;
char y;
scanf("%d", &x);
scanf("\n%c", &y); /* note the \n !! */
printf("%d %c", x, y);
}


**

这如何解决问题?


** 所以你再次输入 '1','2','\n'。第一个 scanf 读取“1”和“2”,将其转换为十进制十二并将 '\n' 留在缓冲区中。下一个 scanf 现在期望在下一个输入的开头有一个 '\n'。它在缓冲区中找到'\n',读取它,然后丢弃它。现在缓冲区是空的,scanf 正在等待用户输入一个字符。假设用户输入“c”,然后输入回车键。'c' 现在分配给 y,而不是“输入”。因此 printf 将在屏幕上输出“12 c”。注意:现在队列中还有一个“\n”。因此,如果您需要对单个字符执行另一个 scanf,则必须先“使用”该 '\n',然后再从用户那里获取另一个字符。

这对于任何其他格式说明符都不是问题,因为它们都忽略输入前的空格。

于 2013-06-13T05:57:36.833 回答