c语言 - 控制台 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. 第一个scanf()sh存储在cmd[]中,并将lsn留在stdin
  2. CCD_ 8占用了CCD_ 9的空间
  3. printf()n sh >>>打印到终端
  4. 第二个scanf()ls存储在shellcmd[]中,将n留在stdin中
  5. eat()从stdin读取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上测试

您可以在手册页中找到:

如果一个流引用一个终端(就像stdout通常做的那样(,它是行缓冲

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

解决方案:

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

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

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

    setvbuf(stdout,NULL,_IONBF,0);
    

最新更新