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

下面的代码在编译后给出了奇怪的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之前提供空间?

将空格添加到格式字符串使scanf能够使用每次按返回时发生的输入中的换行符。 没有空格, 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似乎工作正常,消耗char,float和整数。 但它留下了这样的输入:

 \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


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

使用%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”并将其转换为十进制值十二并将其放入x中。 然后scanf将控制权返回给main函数并返回值1,以便能够成功转换一个条目。 在我们的示例中,我们没有捕获变量中scanf的返回值。 对于健壮的代码,检查scanf()的返回值以确保用户输入正确的数据非常重要。



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



解:
故事的道德是,输入是一个像任何其他的字符,并输入到缓冲区,并从%c 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’,读取它并丢弃它。 现在缓冲区为空,scanf正在等待用户输入一个字符。 假设用户输入’c’,然后输入回车键。 ‘c’现在被分配给y,而不是“输入”。 因此printf将“12 c”输出到屏幕。 注意:现在队列中还有一个’\ n’。 因此,如果您需要为单个字符执行另一次scanf,则必须在从用户处取另一个字符之前“消耗”该“\ n”。

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