[英]unexpected scanf behavior in multi-process program with pipes
對於 UNIX OS class 中的練習,我應該開發一個程序,其中兩個兄弟進程通過 pipe 進行通信。 一個進程(生產者)應該從標准輸出讀取字符串並將它們發送到另一個進程(消費者),然后必須將字符串轉換為大寫並再次將其打印到標准輸出。 字符串“end”終止了兄弟進程和父進程。
該程序運行良好,但是當嘗試從用戶那里讀取整個短語而不是單個字符串時它會崩潰。
這是我的主要內容的一部分:
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, "%s\n", strToUpper(buff));
fflush(stdout);
}
return;
}
printToPipe() 和 readfromPipe() 直接實現 read() 和 write() 系統調用。
意外行為:
一旦輸入第一個短語並轉換為大寫,程序就會無限循環打印出提示和第一個大寫短語(即: Insert string: TEST TEST
)。 尤其是:
scanf("%[^\n]s%*c", buff);
),但后續的 scanfs 將被忽略。 如果我檢查 scanf 返回值,則第一次之后的所有迭代都為 0,盡管我考慮了 \n 字符,但后續的 scanfs 被忽略了
代碼從不讀取'\n'
scanf("%[^\n]s%*c", buff);
是@John Bollinger的問題。
"%[^\n]"
將無限數量的非'\n
字符讀入buff
,可能會溢出buff
。 它比gets()
更糟糕。 如果至少讀取了 1 個非'\n'
字符,則將 null 字符附加到buff
,否則掃描停止。
"s"
匹配一個's'
,這在上述之后是不期望的 - 只有一個'\n'
,因此掃描停止而不消耗任何'\n'
。
格式的 Rest 永遠不會執行。
代碼從不檢查輸入函數的返回值
通過檢查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'
而不是 append 之一。
//fprintf(stdout, "%s\n", strToUpper(buff));
fprintf(stdout, "%s", strToUpper(buff));
這將更好地處理超過BUFFSIZE
的長輸入行,因為多余的字符只留給下一次迭代。
OP 可能需要調整strcmp(line, "end")
測試以考慮可能的尾隨'\n'
。
一個進程(生產者)應該從標准輸出中讀取字符串......
詳細信息:生產者不是從stdout
讀取字符串,而是從stdin
讀取一行到string 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.