I'm relearning (OK, "learning" would be a better term since I never really understood it the first time) piping. My end goal is to execute some shell commands like "ls", get the results into another variable, and do some stuff with it. I imagine I'll end up using commands like "fork" "dup2", and "execvp". But right now I'm at the "Hello World" stage. I have this program and (surprise surprise) it doesn't work. I get a seg fault. I didn't expect it to work really, because, if for no other reason, I imagine I have to actually open the "input" and "output" FILE* variables with fopen or whatever, but since they aren't actually files, I'm not sure how.

Can anyone give me a nudge in the right direction? I'm not even sure if this approach makes any sense at all. Here's the code. It seg faults on line 33. Thanks.

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



int main ()
{
	FILE* output;
	FILE* input;
	int result;
	int bufferSize;
	int filedesc[2];
	char a[100];
	char b[100];
	char c[100];

	result = pipe (filedesc);

	if (result)
	{
		printf ("Problem.  Exiting program.\n");
		exit (1);
	}

	input  = (FILE*) filedesc[0];
	output = (FILE*) filedesc[1];

	strcpy (a, "Hello World");
	bufferSize = strlen (a) + 1;
	fwrite (a, sizeof (char), bufferSize, output);
	fread  (b, sizeof (char), bufferSize, input);

	printf ("%s", b); // should display "Hello World" to stdout

	return 0;
}

Yup...have some suggestions...

1. use read and write instead of fread and fwrite

Edited 6 Years Ago by gerard4143: n/a

Here's a very simple shell of a program...notice the closing of the read/write ends of the pipe..

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

int mystrlen(char *s)
{
	int i = 0;
	while (*s++)
		++i;
	return i;
}

char ch[] = "this is the message to pass along to the other end!\n";

enum PIPES {READ, WRITE};

int main(int argc, char**argv)
{
	char ans;
	int result = 0;
	int hpipe[2];
	pipe(hpipe);

	result = write(hpipe[WRITE], ch, mystrlen(ch));
	close(hpipe[WRITE]);
	
	while (read(hpipe[READ], (char*)&ans, sizeof(char)))
	{
		fputc(ans, stdout);
	}
	close(hpipe[READ]);
	exit(EXIT_SUCCESS);
}

Edited 6 Years Ago by gerard4143: n/a

OK, gerard's code works, but doesn't use any FILE* objects. I'm not 100% sure what Salem was suggesting. I experimented around and did the following. My original attempt at following Salem's advice is below and commented out. I currently have something that displays "Hello World", but the program doesn't exit. It just hangs. It seems to be waiting for user input. Updated code is below.

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

int main ()
{
	FILE* output;
	FILE* input;
	int result;
	int bufferSize;
	int filedesc[2];
	char a[100];
	char b[100];
	char c[100];

	result = pipe (filedesc);

	if (result)
	{
		printf ("Problem.  Exiting program.\n");
		exit (1);
	}

	input = fdopen (filedesc[0], "r");
	output = fdopen (filedesc[1], "w");

	strcpy (a, "Hello World");
	bufferSize = strlen (a) + 1;
	fwrite (a, sizeof (char), bufferSize, /*output*/ stdout);
	fread  (b, sizeof (char), bufferSize, /*input*/ stdin);
	printf ("%s", b); // should display "Hello World" to stdout

	return 0;
}

Try closing the write end of your pipe...

Actually I think you may be better off looking into the function dup2().

Edited 6 Years Ago by gerard4143: n/a

Try closing the write end of your pipe...

I don't think I'm even using the pipe in my code anymore, but I added these lines at the end before "return 0" and I still get the same behavior.

close (filedesc[1]);
	close (filedesc[0]);
	fclose (input);
	fclose (output);

Here's an example of dup2, its was for someone who posted a pipe question here at daniweb...I forgot to post it so you can use it as an example

What does the program do? It forks for each row in the array and each child adds the array elements of its row and then reports the values back to the parent which sums them.

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

#define ARR_ROW 5
#define ELEMENTS_PER_ROW 3

unsigned long longarray[ARR_ROW][ELEMENTS_PER_ROW] = 	{
								{1, 2, 3},
								{4, 5, 6},
								{7, 8, 9},
								{10, 11, 12},
								{13, 14, 15}
							};

enum PIPES {READ, WRITE};

int main(int argc, char**argv)
{
	unsigned long i = 0, tot = 0; 
	int hpipe[2];
	char ch[10];

	signal(SIGCHLD, SIG_IGN);
	pipe(hpipe);

	for (i = 0; i < ARR_ROW; ++i)
	{
		if (fork())
		{
		
		}
		else
		{
			int j = 0; 
			unsigned long ans = 0;
			close(hpipe[READ]);
			dup2(hpipe[WRITE], 1);
			close(hpipe[WRITE]);
			for (j = 0; j < ELEMENTS_PER_ROW; ++j)
				ans += longarray[i][j];
				
			fprintf(stdout, "%lu\n", ans);

			exit(EXIT_SUCCESS);
		}
	}

	close(hpipe[WRITE]);
	dup2(hpipe[READ], 0);
	close(hpipe[READ]);

	for (i = 0; i < ARR_ROW; ++i)
	{
		fgets(ch, 10, stdin);
		tot += strtol(ch, NULL, 10);
	}

	fprintf(stdout, "parent received a total of->%lu\n", tot);
	exit(EXIT_SUCCESS);
}

Edited 6 Years Ago by gerard4143: n/a

Thanks. I've been playing around with my code and have gotten it to work sort of how I want it to, but not completely. I'm going to play around with the code a little more, get it organized and post it a little later. Thanks for the posts. I'm going to leave this as unsolved for now while I experiment some more.

This article has been dead for over six months. Start a new discussion instead.