c-带有管道的多进程程序中的意外scanf行为



对于UNIX操作系统类中的一个练习,我应该开发一个程序,其中两个同级进程通过管道进行通信。一个进程(生产者)应该从stdout中读取字符串并将其发送给另一个进程,后者必须将字符串转换为大写,然后再次将其打印到stdout。字符串";结束";终止兄弟姐妹和父进程。

该程序运行良好,但当试图从用户那里读取整个短语而不是单个字符串时,它会崩溃。

这是我的主要部分:

int main(void) {
int child_status, fd[2];
if (pipe(fd)) {
fprintf(stderr, "Error: Could not create pipe.n");
return EXIT_FAILURE;
}
if (!fork()) {
// child1
producer(fd);
exit(0);
} else if (!fork()) {
// child2
consumer(fd); 
exit(0);
} else {
// father
pid_t pid;
...

生产者流程:

void producer(int *fd) {
char buff[BUFFSIZE];
char *line;

close(fd[0]);
while (1) {
fflush(stdout);
fprintf(stdout, "Insert string:t");
scanf("%[^n]s%*c", buff);
fflush(stdout);
line = strdup(buff);
printToPipe(fd[1], line);

if (!strcmp(line, "end")) // Special string terminates process
return;

sleep(1);
}

return;
}

以及消费者流程:

void consumer(int *fd) {
char *buff;

close(fd[1]);
while (1) {
if ( (buff = readFromPipe(fd[0])) == NULL ) {
close(fd[0]);
return;
}
fprintf(stdout, "%sn", strToUpper(buff));
fflush(stdout);
}

return;
}

printToPipe()和readfromPipe()直接实现了read()和write()系统调用。

意外行为:

一旦输入第一个短语并将其转换为大写,程序将进行无限循环,打印出提示和第一个大写短语(即:Insert string: TEST TEST)。特别是:

  • 尽管我考虑了字符(scanf("%[^n]s%*c", buff);),但会忽略后续扫描。如果我检查scanf返回值,则对于第一次迭代之后的所有迭代
  • 这似乎是一个难题;自我维持";它本身和它的输出:它不等待通过管道的新输入,并不断打印转换后的短语

尽管我考虑了字符,但后续扫描将被忽略

代码从不读取'n'

scanf("%[^n]s%*c", buff);是个问题@John Bollinger。

  1. "%[^n]"将无限数量的非'n字符读取到buff中,可能会溢出buff。它比gets()更糟糕。如果至少读取了1个非'n'字符,则会在buff后面附加一个空字符,否则扫描将停止。

  2. "s"'s'匹配,这在上述之后是不期望的——仅为'n',因此扫描停止而不消耗任何'n'

  3. 该格式的其余部分永远不会执行。

代码从不检查输入函数的返回值

通过检查scanf()的返回值,buff的内容可能是不变的或不确定的。

// scanf("%[^n]s%*c", buff);
if (scanf("%[^n]s%*c", buff) == 1) {
; // OK to use `buff`
}

OP的scanf()可能会消耗第一行的大部分,将'n'留在stdin中,但第二个scanf()调用在尝试读取第一行的'n'时肯定会立即停止。这可能会使buff保持不变。

使用fgets()stdin读取输入的,并另存为字符串@xing

// scanf("%[^n]s%*c", buff);
if (fgets(buff, sizeof buff, stdin) == NULL) {
; // Handle end-of-file or rare input error
break;
}

要从输入行中删除'n',请参阅此答案和其他答案
代码可以将'n'保留在字符串中,并且在打印时不追加。

//fprintf(stdout, "%sn", strToUpper(buff));
fprintf(stdout, "%s", strToUpper(buff));

这将更好地处理超过BUFFSIZE的长行输入,因为多余的字符只是留给下一次迭代。

OP可能需要调整CCD_ 29测试以考虑可能的尾随CCD_。


一个进程(生产者)应该从stdout读取字符串。。。。

详细信息:生产者不是从stdout读取字符串,而是从stdin读取到中。

相关内容

  • 没有找到相关文章

最新更新