scanf()在do-while循环中的未定义行为

huangapple go评论63阅读模式
英文:

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 &#39;\n&#39; 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 &#39;\n&#39; (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 &#39;\n&#39; was printed on the previous line.

Something like:

#include &lt;stdio.h&gt;

int main()
{
    char ch;
    do 
    {
        scanf(&quot;%c&quot; , &amp;ch);
    } while (ch != &#39;\n&#39;);
    
    printf(&quot;%c&quot;, ch);
    printf(&quot;I should show up on a newline&quot;);
    
    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(&quot;%c&quot;, &amp;ch) and stored into ch is the newline character. Hence printf(&quot;%c&quot;, 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(&quot;last value: &#39;%c&#39;\n&quot;, ch);

Note however that the posted code is not a recommended way to read the contents of the input stream:

  • scanf(&quot;%c&quot;, &amp;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 as ch 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 using getchar() and a while loop.

Here is a modified version:

#include &lt;stdio.h&gt;

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 &amp;&amp; c != &#39;\n&#39;) {
        ch = (char)c;
        count++;
    }
    if (count == 0) {
        printf(&quot;no characters entered: &quot;);
        if (c == EOF) {
            printf(&quot;end of file or read error\n&quot;);
        } else {
            printf(&quot;empty line\n&quot;);
        }
    } else {
        printf(&quot;last character on line is &#39;%c&#39;\n&quot;, ch);
        if (c == EOF) {
            printf(&quot;end of file or input error encountered\n&quot;);
        }
    }
    return 0;
}

huangapple
  • 本文由 发表于 2023年2月18日 23:29:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/75494367.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定