为什么我们需要在%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”。
对于任何其他格式说明符,这不是问题,因为它们都在输入之前忽略空格。