2017-04-15 57 views
0

我是一個新的管道C.我想從子進程寫入「hello」&從父進程讀取相同的數據,但是我得到了意想不到的輸出。使用管道時出現意外輸出

我使用這段代碼:

#include<stdio.h> 
#include<unistd.h> 
#include<unistd.h> 
#include<stdlib.h> 

int main() 
{ 
pid_t pid; 
int fds[2]; 
int ret; 
char ch[20]; 

ret = pipe(fds); 
if(ret == -1) 
{ 
    perror("pipe failed"); 
    exit(0); 
} 

pid = fork(); 

if (pid == 0) 
{ 
    printf("Child process\n"); 
    write(fds[1],"Hello",5); 

} 

if (pid > 0) 
{ 

    printf("Parent Process\n"); 
    read(fds[0],ch,15); 
    printf("%s\n",ch); 

} 

return 0; 
} 

我得到這個作爲輸出:

Parent Process 
Child process 
Helloq. 

我不明白爲什麼這個額外的 「Q」。來了 ??

+0

歡迎來到Stack Overflow。 請注意,在這裏說'謝謝'的首選方式是通過 提高投票的好問題和有用的答案(一旦你有足夠的聲譽這樣做),並接受任何 問題最有用的答案,你問(這也給你一個小小的提升,以你的聲望 )。 請參閱[關於]頁面,以及[如何在此處提問 ?]和 [當有人回答我的 問題時,我該怎麼辦? ?](http://stackoverflow.com/help/someone-answers) –

回答

0

在將數據寫入緩衝區之前,在代碼中使用memset()函數,該緩衝區使用恆定字節填充內存。像,

memset(ch,'\0',20); 

完整的代碼可能會幫助你。

#include<stdio.h> 
#include<string.h> 
#include<unistd.h> 
#include<unistd.h> 
#include<stdlib.h> 

int main() 
{ 
     pid_t pid; 
     int fds[2]; 
     int ret; 
     char ch[20]; 
     memset(ch,'\0',20); 
     ret = pipe(fds); 
     if(ret == -1) 
     { 
       perror("pipe failed"); 
       exit(0); 
     } 

     pid = fork(); 

     if (pid == 0) 
     { 
       printf("Child process\n"); 
       write(fds[1],"Hello",5); 

     } 

     if (pid > 0) 
     { 

       printf("Parent Process\n"); 
       read(fds[0],ch,15); 
       printf("%s\n",ch); 
     } 
} 
+1

謝謝大家..great回答 –

2

您正在嘗試寫入6個字節,但將大小設置爲5.您還需要在Hello結尾處發送。

只要改變你寫調用

write(fds[1],"Hello",6); 

,你應該罰款。

0

既然你不記錄了多少字節讀出的管道,你的代碼是印刷已經在ch變量的垃圾。有很多方法來處理它。這段代碼顯示了其中兩個。我使用memset()來確保ch包含一些數據(並且分配確保它是空終止的)。

#include <unistd.h> 
#include <stdlib.h> 
#include <string.h> 
#include <stdio.h> 

int main(void) 
{ 
    pid_t pid; 
    int fds[2]; 
    int ret; 
    char ch[20]; 

    memset(ch, 'X', sizeof(ch)-1); 
    ch[sizeof(ch)-1] = '\0'; 

    ret = pipe(fds); 
    if (ret == -1) 
    { 
     perror("pipe failed"); 
     exit(0); 
    } 

    pid = fork(); 

    if (pid == 0) 
    { 
     printf("Child process\n"); 
     write(fds[1], "Hello", 5); 
    } 
    else if (pid > 0) 
    { 
     printf("Parent Process\n"); 
     int nbytes = read(fds[0], ch, 15); 
     printf("[%s]\n", ch); 
     printf("[%.*s]\n", nbytes, ch); 
     ch[nbytes] = '\0'; 
     printf("[%s]\n", ch); 
    } 
    else 
     fprintf(stderr, "fork() failed\n"); 

    return 0; 
} 

代碼記錄了多少字節寫入(真正勤奮的代碼將確保正確的數據量是書面的,太)。它打印數據3次 - 一次使用原始技術,然後一次使用從管道讀取的字節數來限制輸出,然後空數據終止,以便它可以寫成一個簡單的字符串。

%.*s轉換規範使用兩個值 - 數字和字符串。該數字是將要寫入的最大字節數。如果字符串比這短,那就這樣吧。如果字符串更長,超出的字節將被忽略。

示例輸出:

Parent Process 
[HelloXXXXXXXXXXXXXX] 
[Hello] 
[Hello] 
Child process 

這是管道的程序輸出的結果。在視覺上,在終端上,我通常得到:

Parent Process 
Child process 
[HelloXXXXXXXXXXXXXX] 
[Hello] 
[Hello] 

兩個輸出都有效。注意數據的第一次打印是如何包含一些X的,因爲沒有從管道讀取空字節。

另一種替代方法是讓孩子將空字符結尾的字符串寫入管道:write(fds[1], "Hello", sizeof("Hello"));。其他選項包括在管道上寫入字符串的長度,然後讀取數據,然後讀取長度和許多字節的數據。這是TLV(類型,長度,值)編碼系統的一個小變體 - 類型沒有明確指定,因爲它被假定爲char