Is using low-level pipe/fork is necessary? If no - more easy way - to use popen/pclose system calls.
For your example with ls | grep, this is:
FILE *f = popen("ls");
char buf[1000];
while(fgets(buf, sizeof(buf), f)
call_my_grep(buf);
pclose(f);
This is easy and efficient.