gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 06:58:52 25 4
gpt4 key购买 nike

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

**** 中间操作 ****

进程 ID 5649:
计算:7 和 5 之和为 12

进程 ID 5650:
计算:5 和 9 之和为 14

进程 ID 5651:
计算:5 和 7 之和为 12

进程 ID 5652:
计算:2 和 0 之和为 2

**** 结束行动 ****

进程 ID 5654:
计算:12 和 14 之和为 26

进程 ID 5656:
计算:12 和 2 之和为 14

返回数组[0]:12
返回数组[1]:14
返回数组[2]:12
返回数组[3]:2
返回数组[4]:26
返回数组[5]:14

如果有一行奇数,事情就会变得复杂,因此您必须在计算的任何一点添加零。所以你可以再次设置集合,从而允许计算继续。

比如这一行:ProcessID 5652: Calculation: Sum of 2 and 0 is 2

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

最佳答案

看起来您正在构建一个递归程序。我不知道你为什么把逻辑分成开始、中间和结束操作?

我建议您将其实现为 head::tail 递归,其中每次调用将第一个参数添加到其余参数的运行结果中,或者如果没有参数则返回零:

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

OR 分而治之,其中每个调用要么返回它的单个参数,零表示没有,要么 fork 两个子调用,每个子调用都有剩余参数的一半:
Program -> 0
Program x -> x
Program (N args) -> Program (N+1/2 args) + Program (remaining args)

不需要复杂的内部数据结构,只需要一些简单的数组处理:

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

这是一个不使用退出代码的 perl 版本:
#!/usr/bin/perl
print@ARGV&&(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参数数组 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 的第三个参数在我的例子中具有误导性。

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

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

关于c - Fork() 无法计算命令行参数的最后几位,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2190661/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com