英文:
Undefined behaviour of scanf() in a do-while loop
问题
char ch;
do {
scanf("%c", &ch);
} while (ch != '\n');
printf("%c", ch);
英文:
I'm currently learning C by a book "C Programming a modern approach" and encountered this code. When I tried to run it, after typing consecutive characters like 'abc' and hitting Enter (new line), nothing was printed. Please explain what is going on here.
char ch;
do {
scanf("%c" , &ch);
} while (ch != '\n');
printf("%c", ch);
答案1
得分: 1
你正在要求用户使用 scanf
输入一个字符。这会在一个循环中发生,直到用户输入一个 '\n'
或换行字符(就像按下回车键一样),这时循环将会终止。
然后,你的打印语句将会打印变量 ch
中的字符,在那时它将会是 '\n'
(因为这个变量只存储你输入的最后一个字符)。
当你运行程序时,这个换行字符可能是看不见的,所以你可能看不到它。你可以在循环后添加另一个打印语句,如果那个打印语句从一个新行开始,你就知道 '\n'
是在前一行打印的。
类似这样:
#include <stdio.h>
int main()
{
char ch;
do
{
scanf("%c" , &ch);
} while (ch != '\n');
printf("%c", ch);
printf("我应该显示在一个新行");
return 0;
}
英文:
You're asking the user to input a character using scanf
. This is happening in a loop until the user inputs a '\n'
or newline character (the same as pressing the enter key), which is when the loop will break.
Your print statement will then print the character in the variable ch
, which at that point will be '\n'
(since this variable just stores one character, the last one you typed).
This newline character will probably be invisible when you run your program so you may not be seeing it. You can add another print statement after the loop and if that print statement starts at a newline, you know that the '\n'
was printed on the previous line.
Something like:
#include <stdio.h>
int main()
{
char ch;
do
{
scanf("%c" , &ch);
} while (ch != '\n');
printf("%c", ch);
printf("I should show up on a newline");
return 0;
}
答案2
得分: 0
当我尝试运行它时,输入连续字符如
abc
并按下 <kbd>Enter</kbd>(新行),没有任何输出。
使用发布的代码,即使循环结束,scanf("%c", &ch)
读取并存储到 ch
中的最后一个字节是换行符。因此,printf("%c", ch)
输出这个换行符,看起来好像什么都没打印出来,但实际上打印出了一个不可见的换行符,它会将光标移到下一行。
您可以通过将 printf
调用更改为以下内容来使此更加明确:
printf("最后一个值:'%c'\n", ch);
但请注意,发布的代码不是读取输入流内容的推荐方式:
- 如果流已经到达文件末尾,
scanf("%c", &ch)
可能无法读取字节。未测试此条件会导致未定义的行为(如果输入流是空文件,则ch
不会被修改,因此保持未初始化)或无限循环,因为ch
可能永远不会收到换行符。 - 该代码是一个典型的带有经典错误的
do
/while
示例。最好使用getchar()
和while
循环来编写代码。
以下是修改后的版本:
#include <stdio.h>
int main(void) {
int c; // 必须使用int来区分EOF和所有有效字节值
int count = 0; // 用于判断是否读取了字节
char ch = 0; // 最后读取的字节
// 从输入流中读取所有字节,直到文件结束或换行符
while ((c = getchar()) != EOF && c != '\n') {
ch = (char)c;
count++;
}
if (count == 0) {
printf("未输入字符: ");
if (c == EOF) {
printf("文件结束或读取错误\n");
} else {
printf("空行\n");
}
} else {
printf("行末尾的最后一个字符为 '%c'\n", ch);
if (c == EOF) {
printf("遇到文件结束或输入错误\n");
}
}
return 0;
}
希望这对您有所帮助。
英文:
> When I tried to run it, after typing consecutive characters like abc
and hitting <kbd>Enter</kbd> (new line), nothing was printed.
Well with the posted code, if the loop even finishes, the last byte read by scanf("%c", &ch)
and stored into ch
is the newline character. Hence printf("%c", ch)
outputs this newline and it seems nothing is printed but something is, the newline which is invisible on the terminal but does move the cursor to the next line.
You can make this more explicit by changing the printf
call to this:
printf("last value: '%c'\n", ch);
Note however that the posted code is not a recommended way to read the contents of the input stream:
scanf("%c", &ch)
may fail to read a byte if the stream is at end of file. Failure to test this condition leads to undefined behavior (ch
is unmodified, hence stays uninitialized if the input stream is an empty file) or to an infinite loop asch
may never receive a newline.- this code is a typical example of a
do
/while
with a classic bug. It would be much better to write the code usinggetchar()
and awhile
loop.
Here is a modified version:
#include <stdio.h>
int main(void) {
int c; // must use int to distinguish EOF from all valid byte values
int count = 0; // to tell whether a byte was read at all
char ch = 0; // the last byte read
// read all bytes from the input stream until end of file or a newline
while ((c = getchar()) != EOF && c != '\n') {
ch = (char)c;
count++;
}
if (count == 0) {
printf("no characters entered: ");
if (c == EOF) {
printf("end of file or read error\n");
} else {
printf("empty line\n");
}
} else {
printf("last character on line is '%c'\n", ch);
if (c == EOF) {
printf("end of file or input error encountered\n");
}
}
return 0;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论