Looks like you are building a recursive program. I'm not sure why you have divided the logic into beginning, middle and end operations?
I suggest you either implement this as head::tail recursion, where each invocation adds the first argument to the result of running on the remaining ones, or returns zero if it has no arguments:
Program -> 0
Program head,... -> head + program ...
OR divide and conquer, where each invocation either returns it's single argument, zero for none, or forks two sub-invocations, each with half of the remaining arguments:
Program -> 0
Program x -> x
Program (N args) -> Program (N+1/2 args) + Program (remaining args)
No complex internal data structures are required, just some light array handling:
I should point out that it's a bad idea to communicate value through exit codes, since exit codes have a very limited set of values (256) available for this use, and if your program fails for some reason it may return a surprising value.
Here's a perl version that doesn't use exit code:
#!/usr/bin/perl
print@ARGV&&(shift(@ARGV)+‘$0 @ARGV‘)||0
While this is in perl, which not everyone can read, and perl is doing a lot of work behind the scenes for us, it demonstrates the way you can implement a recursive head::tail sum function using fork and exec.
Here's the c version that uses exit codes:
int forkexec(char**oldargv,char**newargv,char**endargv)
{
if(!fork())
execve(newargv[0]=oldargv[0],newargv,endargv[0]=0);
int b;
wait(&b);
return b>>8;
}
main(int c, char** a)
{
int b;for(b=0;b<c;b++)printf("%s ",a[b]);printf("\n");
exit(!(c-1)?0 // empty head returns 0
:atoi(a[1])+ // convert the head into a number
forkexec(a,a+1,a+c)); // re-invoke on the remaining arguments
}
Please note that this code is NOT SAFE, and it uses undocumented features such as the main
argument array argv
(a
) being NULL terminated. However, it works, and demonstrates recursion using fork, exec and exit codes in c. Running with the debug printf uncommented:
$ gcc sum.c
$ ./a.out 1 2 3 4 5; echo RESULT $?
./a.out 1 2 3 4 5
./a.out 2 3 4 5
./a.out 3 4 5
./a.out 4 5
./a.out 5
./a.out
RESULT 15
As you can see, I haven't used any trees or lists - I just re-invoke the program each time, moving the argument list pointer along by one.
Here's the divide-and-conquer version:
int forkexec(char**oldargv,char**newargv,char**endargv)
{
if(!fork())
execve(newargv[0]=oldargv[0],newargv,endargv[0]=0);
int b;
wait(&b);
return b>>8;
}
main(int c, char** a)
{
//int b;for(b=0;b<c;b++)printf("%s ",a[b]);printf("\n");
exit(!(c-1)?0: // empty leaf is 0
!(c-2)?atoi(a[1]): // leaf returns value
forkexec(a,a,a+1+c/2)+ // Sum left half of children
forkexec(a,a+c/2,a+c)); // Sum right half of children
}
I would like to recommend that you don't use my code; it's ugly, unsafe and deliberately compacted to form a small example for posting here. You should re-write using functional decomposition, error checking and comments, as well as cloning the contents of argv into new, large enough and null terminated arrays. Also the third argument to execve
is misleading in my example.
Uncommenting the debug printf:
int b;for(b=0;b<c;b++)printf("%s ",a[b]);printf("\n");
we get:
$ ./a.out 1 2 3 4 5 6 7 8; echo RESULT $?
./a.out 1 2 3 4 5 6 7 8
./a.out 1 2 3 4
./a.out 1 2
./a.out 1
./a.out 2
./a.out 3 4
./a.out 3
./a.out 4
./a.out 5 6 7 8
./a.out 5 6
./a.out 5
./a.out 6
./a.out 7 8
./a.out 7
./a.out 8
RESULT 36
Which clearly shows the problem being split into increasingly small halves.