我正在编写一个C程序,该程序应该接受其命令行参数,打印它们,删除末尾的两个参数,然后重复直到没有参数保留。例如,调用
a.out alpha beta gamma delta epsilon zeta eta
应打印以下内容:
alpha beta gamma delta epsilon zeta eta
beta gamma delta epsilon zeta
gamma delta epsilon
delta
我提出的代码如下:
int main(int argc, char **argv) {
char **ptr;
for (ptr = argv+1; *ptr; ptr++)
printf("%s ", *ptr);
printf("\n");
if (argc > 3) {
*(ptr-1)=NULL;
execv(*argv, argv+1);
}
printf("Done!");
return 0;
}
这适用于第一个exec调用,但没有进一步的exec结果,并且给定示例的输出是
alpha beta gamma delta epsilon zeta eta
beta gamma delta epsilon zeta
Done!
我无法理解为什么。谁能看到我做错了什么?谢谢!
答案 0 :(得分:4)
关于在fork
之前调用execv
的所有评论都是无稽之谈。在您的情况下,您不希望原始流程继续超出调用execv
的位置,因此绝对没有理由致电fork
。
您的代码无法正常工作的原因是,在调用argv
之前,execv
数组未设置正确。由于argv
数组不正确,execv
会返回错误。通常情况下,execv
不会返回,但如果出现错误,execv
会返回并设置errno
,您可以使用perror
显示该execv
。因此,您应该perror
跟 execv(*argv, argv+1);
perror( "execv returned" );
一样
alpha beta gamma delta epsilon zeta eta
beta gamma delta epsilon zeta
execv returned: No such file or directory
Done!
然后程序的输出是
argv
那么为什么会这样呢?因为argv
列表中的第一个参数是程序本身的名称。这可以通过打印整个for (ptr = argv+1; *ptr; ptr++)
列表来证明。替换此行
for (ptr = argv; *ptr; ptr++)
用这个
./a.out alpha beta gamma delta epsilon zeta eta
alpha beta gamma delta epsilon zeta
execv returned: No such file or directory
Done!
打印所有参数,然后输出
argv[0]
请注意,第一次运行程序时,./a.out
为./a.out
,因此execv
将作为程序名称传递给execv
。但是,第二次调用alpha
时,您将传递alpha
作为程序的名称。由于execv
不是有效的命令名(幸运的是),argv[0]
失败并返回错误。
要解决此问题,您需要确保#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main( int argc, char *argv[] )
{
int i;
for ( i = 1; i < argc; i++ )
printf( "%s ", argv[i] );
printf( "\n" );
if ( argc <= 2 )
{
printf( "Done!\n" );
return( EXIT_SUCCESS );
}
argv[argc-1] = NULL; // drop the last argument
argv[1] = argv[0]; // preserve the program name as the first argument
execv( argv[0], &argv[1] );
perror( "execv returned" ); // should never happen
return EXIT_FAILURE; // exec failed, return error
}
始终是程序的名称。这是更正后的代码
{{1}}