ASharma7
ASharma7

Reputation: 730

Unexpected output while using Pipes

I am a new to pipes in C. I am trying to Write "hello" on the pipe from a child process & read the same from parent process, but I am getting unexpected output.

I using this piece of code:

#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;
}

I am getting this as output :

Parent Process
Child process
Helloq.

I can't understand why this extra "q." is coming ??

Upvotes: 0

Views: 98

Answers (3)

Jonathan Leffler
Jonathan Leffler

Reputation: 754900

Since you don't record how many bytes were read off the pipe, your code is printing the garbage that was already in the ch variable. There are numerous ways to deal with it. This code shows two of them. I used memset() to ensure that ch contained some data (and the assignment makes sure it is null terminated).

#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;
}

The code records how many bytes were written (truly diligent code would ensure that the correct amount of data was written, too). It prints the data 3 times — once using your original technique, then once using the number of bytes read off the pipe to limit the output, and then null-terminating the data so that it can be written as a simple string.

The %.*s conversion specification uses two values — a number and the string. The number is the maximum number of bytes that will be written. If the string is shorter than that, so be it. If the string is longer, the excess bytes are ignored.

Sample output:

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

This was the result of piping the program output. Visually, on the terminal, I usually got:

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

Both outputs are valid. Note how the first printing of the data also includes a number of the X's because there was no null byte read from the pipe.

Another alternative is to have the child write the null of the null-terminated string to the pipe: write(fds[1], "Hello", sizeof("Hello"));. Other options include writing the length of the string on the pipe followed by the data and then reading the length and that many bytes of data. This is a minor variant on a TLV (type, length, value) encoding system — the type is not explicitly specified as it is assumed to be char.

Upvotes: 0

msc
msc

Reputation: 34658

Use memset() function in your code before writing data into buffer, which fill memory with a constant byte. like,

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

Full code may be help you.

#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);
        }
}

Upvotes: 0

Ajay Brahmakshatriya
Ajay Brahmakshatriya

Reputation: 9213

You are trying to write 6 bytes but are setting the size to 5. You need to also send the '\0' at the end of Hello along.

Just change your write call to

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

and you should be fine.

Upvotes: 2

Related Questions