我正在尝试计算从终端输入的一行命令参数的总和。到目前为止,我已经达到了打印出所有内容直到最后几位数的程度。我必须使用fork()来完成我的伴侣程序的所有计算。主程序无法对最终总和进行任何计算。我试图通过创建一个新的动态数组来拉出最后几位数,但如果恰好有100个或更多的单个数字,那么这是无用的。
完成后将从终端打印出来./coordinator 3 4 3 2 1 4 5 4 3 2 4 3 2
****开始运营****
进程ID:5642 计算:3和4之和为7
进程ID:5643 计算:3和2之和为5
进程ID:5644 计算:1和4之和为5
进程ID:5645 计算:5和4之和为9
进程ID:5646 计算:3和2之和为5
进程ID:5647 计算:4和3之和为7
进程ID:5648 计算:2和0之和为2
****中间操作****
ProcessID 5649: 计算:7和5之和为12
ProcessID 5650: 计算:5和9之和为14
ProcessID 5651: 计算:5和7之和为12
ProcessID 5652: 计算:2和0之和为2
****结束操作****
ProcessID 5654: 计算:12和14之和为26
ProcessID 5656: 计算:12和2之和为14
return_array [0]:12
return_array [1]:14
return_array [2]:12
return_array [3]:2
return_array [4]:26
return_array [5]:14
在存在奇数行的情况下,事情变得复杂,因此您必须在计算的任何位置添加零。因此,您可以再次进行设置,从而允许继续计算。
如此行:ProcessID 5652:计算:2和0之和为2
如果我使数字更复杂(一开始就有更多的数字),“结束操作”之后的部分变得更大,因此更难以将最后几个总和拉出来以一个总和结束。我无法将这些数字拉出来。
答案 0 :(得分:3)
看起来你正在构建一个递归程序。我不确定你为什么把逻辑划分为开始,中间和结束操作?
我建议您将其实现为head :: tail recursion,其中每次调用都会将第一个参数添加到剩余的运行结果中,或者如果没有参数则返回零:
Program -> 0
Program head,... -> head + program ...
OR分而治之,每次调用都返回它的单个参数,零返回,或者分叉两个子调用,每个调用都有剩余参数的一半:
Program -> 0
Program x -> x
Program (N args) -> Program (N+1/2 args) + Program (remaining args)
不需要复杂的内部数据结构,只需要一些光阵列处理:
我应该指出,通过退出代码传递价值是一个坏主意,因为退出代码具有非常有限的一组值(256)可用于此用途,并且如果您的程序由于某种原因失败,它可能会返回令人惊讶的值。
这是一个不使用退出代码的perl版本:
#!/usr/bin/perl
print@ARGV&&(shift(@ARGV)+‘$0 @ARGV‘)||0
虽然这是perl,并不是每个人都可以阅读,并且perl在幕后为我们做了很多工作,但它演示了使用fork和exec实现递归head :: tail sum函数的方法。 / p>
这是使用退出代码的c版本:
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
}
请注意,此代码不安全,并且它使用未记录的功能,例如main
参数数组argv
(a
)被NULL终止。但是,它可以工作,并使用c中的fork,exec和exit代码演示递归。使用debug printf运行取消注释:
$ 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
正如你所看到的,我没有使用任何树或列表 - 我每次都重新调用程序,将参数列表指针一一移动。
这是分而治之的版本:
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
}
我建议您不使用我的代码;它是丑陋的,不安全的,故意压缩形成一个小例子发布在这里。您应该使用功能分解,错误检查和注释重写,以及将argv的内容克隆到新的,足够大和空终止的数组中。另外,execve
的第三个参数在我的例子中具有误导性。
取消注释debug printf:
int b;for(b=0;b<c;b++)printf("%s ",a[b]);printf("\n");
我们得到:
$ ./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
这清楚地表明问题被分成越来越小的一半。