控制台 I/O:printf 和 scanf 未按预期顺序出现

Console I/O : printf & scanf not occurring in expected order

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void eat() // clears stdin upto and including \n OR EOF
{
    int eat;while ((eat = getchar()) != '\n' && eat != EOF);
}

int main(){

    printf("\n COMMAND : "); char cmd[21]=""; scanf("%20s",cmd);

    if(strcmp(cmd,"shell")==0||strcmp(cmd,"sh")==0)
    {
        getchar(); // absorb whitespace char separating 'shell' and the command, say 'ls'
        while(1)
        {
            printf("\n sh >>> "); // print prompt
            char shellcmd[1024]=""; // str to store command
            scanf("%1023[^\n]",shellcmd); eat(); // take input of command and clear stdin

            if(strcmp("close",shellcmd)==0||strcmp("x",shellcmd)==0)
                break;
            else
                system(shellcmd);
        }
    }
}

在代码中,发生了一些我无法捕捉到的异常行为。

输入 sh ls 并按 [ENTER] 后,预期的响应是:

  1. 第一个 scanf()cmd[] 中存储 sh 并在 stdin 中留下 ls\n
  2. getchar()占了 space.
  3. printf() 打印 \n sh >>> 到终端
  4. 第二个 scanf()shellcmd[] 中存储 ls,在标准输入
  5. 中留下 \n
  6. eat() 从标准输入中读取 \n,将其留空
  7. system("ls")被执行

即结果应该是这样的:

 COMMAND : sh ls

 sh >>>
 file1 file 2 file3 ...

 sh >>> | (cursor)

但是

我得到的:

COMMAND : sh ls

file1 file2 file3 ...
 sh >>> 
 sh >>> | 

显然,第二个 scanf()shell() 正在执行 before printf() ,或者至少是 my假设。

怎么了?

使用 cc -Wall -Wextra -pedantic 在 Clang 和 GCC 上编译并在 MacOS 上的 bash 和 Linux

上测试

您可以在 man page 中找到:

If a stream refers to a terminal (as stdout normally does) it is line buffered

因此,当 printf 不包含换行符时,您可能会延迟看到打印的消息。在另一端,一旦发送下一个 printf 的前导换行符,就会显示上一个消息。

解决方案:

  1. 在您的消息末尾添加换行符printf("\n sh >>> \n");

  2. 通过调用 flush() 函数 (fflush(stdout))

    强制显示当前缓冲区,即使没有换行符
  3. 使用setvbuf()函数

    改变当前的stdout缓冲行为
    setvbuf(stdout,NULL,_IONBF,0);