以下代码在编译后立即给出了奇怪的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之前提供空间?
答案 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))。该指令在输入中匹配任意数量的空白,包括无空格。
...
只要您在循环中使用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'。
这对任何其他格式说明符都不是问题,因为它们之前都忽略了空格 输入。