2010-02-03 31 views
2

我试图计算从终端输入的一行命令参数的总和。到目前为止,我已经到了将打印出所有东西的位置,直到最后几位。我必须利用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

**** MIDDLE OPERATIONS ****

的ProcessID 5649: 计算:7和5总和为12

的ProcessID 5650: 计算:5萨姆和9为14

的ProcessID 5651: 计算:5萨姆和图7是12

的ProcessID 5652: 计算:2和0总和为2个

**** ENDING OPERATIONS ****

的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

事情变得COM在存在一行奇数的地方进行拼接,因此您必须在计算中的任意点添加一个零。所以你可以再次设置这个设置,这样就可以继续计算了。

如这一行:的ProcessID 5652:计算:2总和,0是2

如果我让数字更加复杂,部分(在开始的时候更多的数字)后,“结束操作”变得更大从而使得把最后几笔款项拉到最后总计一笔就更难了。我无法拉出这些数字。

+0

你应该考虑发布你的代码。 – 2010-02-03 08:56:06

+0

我发布了迄今为止我所拥有的内容。 – foobiefoob 2010-02-03 09:01:49

+1

什么能阻止你迭代argv数组?家庭作业标签也许? – 2010-02-03 13:06:19

回答

3

看起来你正在构建一个递归程序。我不确定你为什么将逻辑分为开始,中间和结束操作?

我建议你要么实现此作为头::尾递归,其中每个调用添加的第一个参数上,其余的正在运行的结果,或返回零,如果它没有参数:

Program -> 0 
Program head,... -> head + program ... 

或分而治之,其中每个调用或者返回它的一个参数,因为没有零,或叉两个子调用,每次半的其余参数:

Program -> 0 
Program x -> x 
Program (N args) -> Program (N+1/2 args) + Program (remaining args) 

,不需要复杂的内部数据结构,只是一些光阵列处理:

我应该指出,通过退出代码传递值是一个坏主意,因为退出代码有一个非常有限的值(256)可用于此用途,并且如果您的程序由于某种原因失败,它可能会返回一个令人惊讶的价值。

下面是不使用退出代码的perl版本:

#!/usr/bin/perl 
[email protected]&&(shift(@ARGV)+‘$0 @ARGV‘)||0 

虽然这是perl,它不是每个人都可以阅读,和Perl是做了很多幕后工作,对于我们来说,演示了如何使用fork和exec实现递归head :: tail sum函数的方式。

下面是一个使用退出代码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参数数组argva)被NULL终止。然而,它的工作原理,并演示递归使用fork,exec和退出代码在c中。与调试的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的第三个参数在我的例子中是误导性的。

取消对调试的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 

,清楚地显示问题被分裂成越来越小的一半。

+0

作为链接列表实现? – foobiefoob 2010-02-03 09:14:23

+0

谢谢,现在我对如何去做这件事有了一个想法。 – foobiefoob 2010-02-03 14:37:46