Nathan1324
Nathan1324

Reputation: 168

Unix pipe is taking input but not displaying output

I'm attempting to create a pipe for a C program that takes pre.c and processes it using a child process and takes sort.c and processes it as a parent process. When I execute the pipe executable I get prompted for the necessary input, but then when I ctrl-d there is no output displaying. When I run ./pre | ./sort more of the same -- no output. When I run these individual executables alone they seem to work fine. Any ideas what is occurring to prevent the output from being processed properly?

pre.c:

#include <stdio.h>

typedef struct{
   char  name[4];
   int   population;
} State;

enum { MAX_STATES = 10 };

int main()
{
    State myStates[MAX_STATES];

    int i, j;

    // Function to read in multiple lines (up to 10) of user input; loop 
    // controls in place, detects format problems, prevents string buffer 
    // overflows.
    for (i = 0; i < MAX_STATES; i++)
    {
        if (scanf("%2s %d\n", myStates[i].name, &myStates[i].population) != 2)
            break;
    }

    printf("\n");

    // Function to output (stdout) array of State structs that exceed 10 
    // population. 
    for(j = 0; j < i; j++)
        {
            if(myStates[j].population >= 10)
            {
                printf("%s %d\n", myStates[j].name, myStates[j].population);
            }
        }

    return 0;
}

sort.c:

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

typedef struct{
   char  name[3];
   int   population;
} State;

enum { MAX_STATES = 10 };

int main()
{
    State myStates[MAX_STATES];

    int i, 
        j,
        k, 
        count = 0;

    char temp[3];

    while( scanf("%s%d", myStates[i].name, &myStates[i].population)!= EOF)
        i++;

    count = i;

    // for(i = 0; i < MAX_STATES; i++)
    // {
    //     if (scanf("%2s %d\n", myStates[i].name, &myStates[i].population) != 2)
    //         break;
    //     count++;
    // }

    printf("\n");

    // Function to sort necessary input 
    for(j = 0; j < (count-1); j++)
        {
            strcpy(temp, myStates[j].name);
            for(k = j + 1; k < count; k++)
            {
                if(strcmp(myStates[j].name, myStates[k].name) > 0)
                {
                    strcpy(myStates[j].name, myStates[k].name);
                    strcpy(myStates[k].name, temp);
                }
            }
        }

     for( i=0; i < count; i++)
     {
        printf("%s\n", myStates[i].name);
     }

    return 0;
}

pipe.c:

#include <stdio.h>

int main()
{
    int pid;
    int fd[2];
    pid = pipe(fd);
    fork();

    if(pid < 0) // error case
        printf("could not create pipe\n");
    else if(pid == 0)
    {
        // Child Process
        close(1);
        dup(fd[1]);
        close(fd[0]);
        close(fd[1]);
        execvp("./pre", 0);
    }
    else
    {
        // Parent Process
        close(0);
        dup(fd[0]);
        close(fd[0]);
        close(fd[1]);
        execvp("./sort", 0);
    }

    return 0;
}

Input:

$ ./pipe
TX 32
RI 3
CA 53

Output:

Upvotes: 0

Views: 376

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 755044

Fixed code — but sort.c now uses qsort() rather than your home-brew sort which was not working for me on bigger data sets.

The programs compile cleanly on a Mac running macOS Sierra 10.12.6 using GCC 7.1.0 and command lines like:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
>     pre.c -o pre
$

There were numerous small changes needed to make that work — removed variables, added headers, etc.

One of the key changes in pipe.c is capturing the pid from fork(), not pipe().

pre.c

#include <stdio.h>

typedef struct
{
    char name[3];
    int population;
} State;

enum { MAX_STATES = 10 };

int main(void)
{
    State myStates[MAX_STATES];

    int i, j;

    for (i = 0; i < MAX_STATES; i++)
    {
        if (scanf("%2s %d\n", myStates[i].name, &myStates[i].population) != 2)
            break;
    }

    for (j = 0; j < i; j++)
    {
        if (myStates[j].population >= 10)
        {
            printf("%s %d\n", myStates[j].name, myStates[j].population);
        }
    }

    return 0;
}

sort.c

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

typedef struct
{
    char name[3];
    int population;
} State;

static int cmp(const void *v1, const void *v2)
{
    const State *s1 = (State *)v1;
    const State *s2 = (State *)v2;
    return strcmp(s1->name, s2->name);
}

enum { MAX_STATES = 10 };

int main(void)
{
    State myStates[MAX_STATES];

    int count = 0;

    for (int i = 0; i < MAX_STATES; i++)
    {
        if (scanf("%s %d", myStates[i].name, &myStates[i].population) != 2)
            break;
        count++;
    }

    qsort(myStates, count, sizeof(myStates[0]), cmp);

    for (int i = 0; i < count; i++)
    {
        printf("%s\n", myStates[i].name);
    }

    return 0;
}

pipe.c

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

int main(void)
{
    int fd[2];
    if (pipe(fd) != 0)
    {
        fprintf(stderr, "could not create pipe\n");
        return(1);
    }

    int pid = fork();
    if (pid < 0)
    {
        fprintf(stderr, "could not fork\n");
        return(1);
    }
    else if (pid == 0)
    {
        close(1);
        if (dup(fd[1]) != 1)
            return(1);
        close(fd[0]);
        close(fd[1]);
        char *arg1[] = { "./pre", 0 };
        execv(arg1[0], arg1);
        fprintf(stderr, "failed to execute %s\n", arg1[0]);
        return(1);
    }
    else
    {
        close(0);
        if (dup(fd[0]) != 0)
            return(1);
        close(fd[0]);
        close(fd[1]);
        char *arg2[] = { "./sort", 0 };
        execv(arg2[0], arg2);
        fprintf(stderr, "failed to execute %s\n", arg2[0]);
        return(1);
    }

    return 0;
}

Sample data

CA 39250017
TX 27862596
FL 20612439
NY 19745289
IL 12801539
PA 12784227
OH 11646273
GA 10310371
NC 10146768
MI 9928301

(Population figures from Wikipedia.)

Output from ./pre < states

CA 39250017
TX 27862596
FL 20612439
NY 19745289
IL 12801539
PA 12784227
OH 11646273
GA 10310371
NC 10146768
MI 9928301

Output from ./pre < states | ./sort

CA
FL
GA
IL
MI
NC
NY
OH
PA
TX

Output from ./pipe < states

CA
FL
GA
IL
MI
NC
NY
OH
PA
TX

Upvotes: 2

Related Questions