【问题标题】:Console I/O : printf & scanf not occurring in expected order控制台 I/O:printf 和 scanf 未按预期顺序发生
【发布时间】:2021-01-04 03:15:44
【问题描述】:
#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()sh 存储在cmd[] 中,并将 ls\n 留在stdin 中。
  2. getchar() 占用 空间。
  3. printf() 打印 \n sh &gt;&gt;&gt; 到终端
  4. 第二个scanf()shellcmd[]中存储ls,在标准输入中留下\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(),或者至少这是我的假设。

怎么了?

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

【问题讨论】:

    标签: c shell io stdin console-input


    【解决方案1】:

    您可以在man page 中找到:

    如果一个流引用一个终端(就像标准输出通常那样)它是行缓冲的

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

    解决方案:

    1. 在邮件末尾添加换行符printf("\n sh &gt;&gt;&gt; \n");

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

    3. 使用setvbuf() 函数更改当前的stdout 缓冲行为

      setvbuf(stdout,NULL,_IONBF,0);
      

    【讨论】:

    • 哦,我看到 0 0 ...所以它不是我的程序有问题:)
    • @user13863346 试试看(我会从选项 2 开始),让我知道它是否有效
    • 是的,这行得通……它已修复! flush() 有效,格式字符串末尾的'\n' 也有效。我被第三个吓倒了,所以不会尝试;)
    • @user13863346 只需在打印任何内容之前致电setvbuf(stdout,NULL,_IONBF,0);
    • 问题出在非常不直观的基本 C 控制台 api...
    猜你喜欢
    • 2011-02-25
    • 2020-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    相关资源
    最近更新 更多