Toy shell not piping correctly

I'm virtually certain this is what you're trying to do. Apologies in advance for the sloppy coding. its somewhat late here and I really should be sleeping right now:

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>

#define READ 0
#define WRITE 1

// ps -A | grep argv[1] | wc -l

int main( int argc, char** argv )
{
    // start of input block
    if ( argc != 2 )
    {
        std::cout << "Usage: ./a.out arg1" << std::endl;
        return 0;
    }
    
    // make local copy of argument
    std::string in = argv[1];
    int fd1[2], fd2[2], pid;
    
    // allocate two pipe sets
    if (pipe(fd1) < 0 || pipe(fd2) < 0)
    {
        perror("Failed to create pipe.");
        return EXIT_FAILURE;
    }
    
    // launch first child process.
    if ((pid = fork()) < 0)
    {
        perror("Failed to fork child(1)");
        return EXIT_FAILURE;
    }
    
    if (pid == 0)
    {
        // wc -l process. 
        //  stdin  = fd2(read)
        close(fd1[READ]);
        close(fd1[WRITE]);
        close(fd2[WRITE]);
        dup2(fd2[READ],STDIN_FILENO);
        execlp("wc","wc","-l",NULL);
    }
    
    // fork again. this time for grep
    if ((pid = fork()) < 0)
    {
        perror("Failed to fork child(2)");
        return EXIT_FAILURE;
    }
    
    if (pid == 0)
    {
        // grep argv[1] process.
        //  stdin  = fd1(read)
        //  stdout = fd2(write)            
        close(fd1[WRITE]);
        close(fd2[READ]);
        dup2(fd2[WRITE], STDOUT_FILENO);
        dup2(fd1[READ], STDIN_FILENO);
        execlp("grep", "grep", in.c_str(), NULL);
    }
    
    //  fork once more. this time for ps -A
    if ((pid = fork()) < 0)
    {
        perror("Failed to fork child(3)");
        return EXIT_FAILURE;
    }
    
    if (pid == 0)
    {
        // ps -A process.
        //  stdout = fd1(write)
        close(fd2[WRITE]);
        close(fd2[READ]);
        close(fd1[READ]);
        dup2(fd1[WRITE], STDOUT_FILENO);
        execlp("ps", "ps", "-A", NULL);
    }
    
    int stat=0;
    wait(&stat);

    return EXIT_SUCCESS;
}

On my system, ps -A reports 141 lines, of those 41 have the word System somewhere within, verified by simply running ps -A | grep System | wc -l. The above code generates precisely the same output.