简体   繁体   中英

Using a pipe to read array of strings with C

I am learning about using pipes with C right now, and I am having some difficulty writing a list of strings, one-by-one, to the pipe in the child process, and then read them from the pipe in the parent process. Here is my current code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

int main()
{
    int pfd[2];
    char buf[1000];
    int cfork;

    if (pipe(pfd) == -1) {
        exit(1);
    }

    cfork = fork();

    if (cfork == -1) {
        printf("Fork Failed\n");
        exit(1);
    }
    else if (cfork == 0) {
        printf("Child Process\n");

        char *fruit[] = {
            "Orange", "Apple",
            "Banana", "Pear"
        };

        int num_fruit = 4;
        for (int i = 0; i < num_fruit; i++) {
            printf("Current fruit: %s\n", fruit[i]);
            write(pfd[1], fruit[i], (strlen(fruit[i])));
        }
        _exit(0);
    }
    else {
        printf("Parent Process\n");
        read(pfd[0], buf, sizeof(buf));
        printf("Fruit Fetched: %s\n", buf);
        wait(NULL);
    }

    return 0;

}

What I am trying to do, is in the child, read a fruit string, write it to the pipe, and have the parent read this string and print it, until all the strings have been printed. My trouble is that the child, since it's in a loop, just keeps adding each string to the buffer, so the program, as it stands, prints out "OrangeAppleBanana". I am pretty sure I will need a loop in the parent as well, but when I've tried a while loop that waits for some end condition string sent by the child (for example "done"), my program still gets stuck in an infinite loop.

What is the most straightforward way, for someone new to C, to write strings in the child one -by-one, and have the parent process print them out one-by-one?

EDIT

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

int main()
{
    int pfd[2];
    int cfork;

    if (pipe(pfd) == -1) {
        exit(1);
    }

    cfork = fork();

    if (cfork == -1) {
        printf("Fork Failed\n");
        exit(1);
    }
    else if (cfork == 0) {

        int numbers[] = {
            1, 2,
            3, 4
        };

        int limit = 4;
        close(pfd[0]);
        for (int i = 0; i < limit; i++) {
            printf("Child - Current Number: %d\n", numbers[i]);
            write(pfd[1], &numbers[i], sizeof(numbers[i]));
        }
        close(pfd[1]);
        _exit(0);
    }
    else {

        int temp;
        int reads = 4;
        close(pfd[1]);
        for (int i = 0; i < reads; i++) {
            read(pfd[0], &temp, sizeof(temp));
            printf("Parent - Number Fetched: %d\n", temp);
        }
        close(pfd[0]);
        waitpid(-1, NULL, 0);
    }

    return 0;

This is my new code, where I use integers instead of strings. Seems to work so far. Still not sure what I was doing wrong with strings though.

I believe your problem is with "strings". Strings in C are null terminated, so when you are sending them via pipe, receiver(parent) doesn't know where a string ends. Strlen does count the number of characters in a string, but not the null charatter. You should do:

 write(pfd[1], fruit[i], (strlen(fruit[i]))+1);

Parent can now know when and where to split your string.

The other problem is that you need to loop in the parrent as well. You need to set up a condition in the loop, which checks for EOF. In your example, where you know you are going to receive 4 fruits, you can just loop 4 times.

It's a good practice to close read and write end of pipes you don't need. In your example, child should close the reading end, while parent should close the writing end. You can do this with:

close(pfd[0]);  //use this in child

close(pfd[1]);   //use this in parent

You should also get used to closing all descriptors you don't need. In your example, you should close the pipe in both child and parent process after you are finished with writing / reading. This way, you could create a read loop condition, which closes after EOF. (When child closes pipe, receiver can end)

As an extra tip, try error reporting with "perror" http://www.tutorialspoint.com/c_standard_library/c_function_perror.htm

//Child
close(pfd[0]); // Close read end this blocks if parent is reading from pipe
write(pfd[1]...); // write data into pipe
close(pfd[1]); // close write end of pipe now the pipe is ready to read

// Parent
close(pfd[1]); // close write end of pipe blocks if child is writing to pipe.
read(pfd[0] ...);
close(pfd[0]..); // close read end so pipe is ready to write to.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM