2017-04-15 58 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