Fork()无法计算命令行参数的最后几位数

时间:2010-02-03 08:46:33

标签: c unix fork

我正在尝试计算从终端输入的一行命令参数的总和。到目前为止,我已经达到了打印出所有内容直到最后几位数的程度。我必须使用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

如果我使数字更复杂(一开始就有更多的数字),“结束操作”之后的部分变得更大,因此更难以将最后几个总和拉出来以一个总和结束。我无法将这些数字拉出来。

1 个答案:

答案 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参数数组argva)被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

这清楚地表明问题被分成越来越小的一半。