为什么我们需要在%c之前放置空间?

时间:2013-06-13 04:16:24

标签: c character

以下代码在编译后立即给出了奇怪的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

然后我的问题是为什么我们不在%d之前给%f和空格前提供空间?为什么我们只需要在%c之前提供空间?

2 个答案:

答案 0 :(得分:13)

将空格添加到格式字符串使scanf能够使用每次按 return 时发生的输入中的换行符。如果没有空格,name[i]将收到字符'\n',而真正的字符会被%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似乎工作正常,消耗char,浮点数和整数。但它留下了这样的输入:

\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


只要您在循环中使用scanf%c,就会出现这种问题。因为,假设自由格式输入,换行符可以在任何地方发生。因此,通过使用双层方法来避免整个问题是很常见的。您将输入的读入缓冲区(使用fgets);切断愚蠢的换行符;然后使用sscanf代替scanf从缓冲区(字符串)中读取,而不是直接从文件中读取。

答案 1 :(得分:4)

  

使用%c输入错误

考虑以下代码片段:

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

行为:
当您运行上述程序时,将调用第一个scanf   等待您输入十进制数字。说你输入   12(那是ASCII'1'和ASCII'2')。然后你点击“输入”键   发出输入结束的信号。接下来程序将执行第二个   scanf,除了你会注意到程序没有等你   输入一个字符,然后向右前进到输出12   通过'\ n'。



  

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



  

缓冲区中剩下的是'\ n'。接下来,第二个scanf是   叫它,它期待一个角色。由于缓冲区已经有了   其中的'\ n'字符,scanf看到,从缓冲区中获取,   并把它放在y。这就是为什么当你之后执行printf时,   12,“输入”将打印到屏幕上。



  

解决方案:
故事的道德是,输入是一个像任何其他人一样的角色,   然后输入到缓冲区,并由%c从缓冲区中消耗   像任何其他ASCII字符一样。要解决此问题,请尝试使用此代码   代替:


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',读取它并丢弃它。现在   buffer为空,scanf正在等待用户输入一个字符。   假设用户输入'c',然后输入回车键。 'c'现在   分配给y,而不是“输入”。因此printf会输出“12 c”   屏幕。注意:现在队列中还有一个'\ n'。因此,如果   你需要为一个角色做另一个scanf   在从用户那里获取另一个角色之前“消耗”'\ n'。

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