首页 > 解决方案 > 控制台 I/O:printf 和 scanf 未按预期顺序发生

问题描述

#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. 1stscanf()存放sh在. cmd[]_ ls\n_stdin
  2. getchar()占用 空间。
  3. printf()打印\n sh >>>到终端
  4. 第二个scanf()存储lsshellcmd[],离开\n标准输入
  5. eat()从标准输入读取\n,将其留空
  6. system("ls")被执行

即结果应该是这样的:

 COMMAND : sh ls

 sh >>>
 file1 file 2 file3 ...

 sh >>> | (cursor)

我得到什么:

COMMAND : sh ls

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

显然,第二个scanf()之前shell()正在执行,或者至少这是的假设。 printf()

有什么问题?

在 Clang 和 GCC 上编译并cc -Wall -Wextra -pedantic在 MacOS 和 Linux 上的 bash 上进行测试

标签: cshelliostdinconsole-input

解决方案


正如您可以在手册页中找到的那样:

如果流引用终端(如标准输出通常那样),则它是行缓冲的

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

解决方案:

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

  2. flush()通过调用函数 ( fflush(stdout))强制显示当前缓冲区,即使没有换行符

  3. 使用函数更改当前的标准输出缓冲行为setvbuf()

    setvbuf(stdout,NULL,_IONBF,0);
    

推荐阅读