int print_args(int argc, char** argv, const char* msg)
{
if (msg != NULL) printf("%s", msg);
printf(" %d arguments on command line:\n", argc-1);
for (int i = 1; i < argc; i += 1)
printf("\t#%d:\t%20s\n", i, argv[i]);
return 0;
}
型 在程序结束时,生成的参数应该是free 'd,这是一个很好的实践。
示例代码
#define EXPECTED 6
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int print_args(int argc, char** argv, const char*);
int main(int argc, char** argv)
{
const char* prefix = "(Generated) argv[";
// if there at least EXPECTED we are good to go
if (argc == EXPECTED)
{
print_args(argc, argv, "argument(s) ok");
return 0;
}
int missing = EXPECTED - argc;
// missing at least 1
printf(" %d argument (s) missing\n", missing);
char** nd_argv = malloc((1 + EXPECTED) * sizeof(char*));
nd_argv[0] = argv[0]; // the program name
nd_argv[EXPECTED] = NULL; // the sentinel pointer
for (int i = 1; i < EXPECTED; i += 1)
{
if (i < argc)
{
printf(
" argv[%d] is present: \"%s\"\n", i,
argv[i]);
nd_argv[i] = argv[i];
continue;
}
char* one_arg = malloc(strlen(prefix) + 3);
sprintf(one_arg, "%s%d]", prefix, i);
printf(
" argv[%d] created as \"%s\"\n", i, one_arg);
nd_argv[i] = one_arg;
}
argc = EXPECTED;
argv = nd_argv;
print_args(argc, argv, NULL);
for (int i = argc - missing; i < argc; i += 1)
{
printf(" free argv[%d]\n", i);
free(argv[i]);
}
free(argv[EXPECTED]); // free the sentinel
free(nd_argv); // and the array itself
return 0;
}
int print_args(int argc, char** argv, const char* msg)
{
if (msg != NULL) printf("%s", msg);
printf(" %d arguments on command line:\n", argc - 1);
for (int i = 1; i < argc; i += 1)
printf("\t#%d:\t%20s\n", i, argv[i]);
return 0;
}
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
if (argc == 1) {
argv[1] = malloc(7);
if (!argv[1]) exit(EXIT_FAILURE);
strcpy(argv[1], "foobar");
}
// rest of code that keeps `argc` unchanged
// also do not pass argc and argv to some code
// that reasonably expects argv[argc] to be NULL
if (argc == 1) {
free(argv[1]);
// return to the initial situation in case the library code needs it
argv[1] = NULL;
}
}
size_t len0 = strlen(argv[0]);
argv[0][len0] = 'X'; // argv[0] is no longer a string
argv[0][len0+1] = 0; // possible UB: that byte may not belong to the array
9条答案
按热度按时间nkkqxpd91#
您可以使用
argc
来了解argv
中有多少个元素,并相应地做出响应。第一个值是程序的名称,所有后续值都是用户输入。字符串
c90pui9n2#
Standard并没有说要修改
argv
引用的指针数组(不是argv
本身和这个数组的元素引用的C字符串)。你需要:字符串
rggaifut3#
作弊!你的编译器会很高兴
字符串
wa7juj8i4#
如果用户没有输入任何东西,那么
argv[1]
就不存在,因为在这种情况下argc==1
和argv[1]
将是越界访问。您可以做的是创建一个工作副本,以满足您在
argv
为空的情况下的需求。例如:字符串
在本例中,
argv_workcopy
是一个指针的可变长度数组(VLA),它的大小可能与argc
一样大,或者在没有任何命令行参数的情况下,它的大小为2
。默认值输入为
argv_workcopy[1] = "";
。这是一个只读的空字符串,但请注意,你也可以让这个点读/写内存,如malloc
调用返回的内存。如果有
argv
字符串传递,它们将覆盖默认值。如果没有,将使用默认值。因此,如果我将此程序称为myprog hello world
,那么它将打印hello
,但如果我将其称为myprog
,它将打印一个空行。(Also这个程序不会在
argv
的末尾添加一个NULL sentinel,所以如果你需要这个功能,你需要增加ARGV_MIN
并手动分配一个NULL。wsewodh25#
程序加载器的使命是在程序开始时管理
argc
和argv
。字符串
这些都是声明的,一个
int
和一个char**
。但是argc
可以是unsigned
,argv
可以是char*[]
,或者它们可以被声明为const
。它只是一个函数和它的参数。* 特殊的事情 * 发生在程序执行之前和之后。所以你可以按照你的想法使用它。审议这个
示例
这是示例的输出(需要5个参数)对于某些参数,没有参数或很少参数。仅举例子,如图所示生成并插入缺少的参数,并在退出时插入
free
。第一个参数是程序名,数组argv
以NULL
指针结束,如果需要,会生成一个新的argv
数组,并替换初始数组,这样程序就可以继续运行,而不需要知道命令行中是否提供了参数。输出
型
一般来说,如果你需要修改这些参数,只修改它们比在程序中创建和使用新的参数数组更方便。它可以只是旧程序中的一个修复,所以到处去修改是很无聊的。
示例中的此函数打印参数数组,并且不关心它们是否被篡改:
型
在程序结束时,生成的参数应该是
free
'd,这是一个很好的实践。示例代码
型
gev0vcfq6#
C标准有很多规则管理
argc
和argv
。参见C11 5.1.2.2.1p2
argv[argc]
应该是空指针。argc
和argv
以及argv
数组指向的字符串应可由程序修改,并在程序启动和程序终止之间保留其最后存储的值。因此,在
argc == 1
的情况下,您可以将NULL
更改为其他内容:字符串
请注意,在这种情况下,
argv[2]
不存在。您无法更改它。还要注意的是,虽然
argv[0]
是一个普通的旧的常规字符串(可以是任何其他argv
元素),但您不知道底层数组的大小,只知道它至少是strlen(argv[0]) + 1
。型
bakd9h0s7#
如果用户没有在程序名后输入任何命令行参数,则
main
函数接收值为1
的argc
,argv
指向一个2char *
的数组,第一个可能指向一个带有程序名的字符串,第二个是空指针,而不是空字符串。如果你试图用
strcpy(argv[1], "default")
覆盖argv[1]
中缺少的参数,你肯定会调用undefined行为,因为argv[1]
是一个空指针,这是你观察到的分段错误的一个很好的解释。C标准在5.1.2.2.1程序启动中规定,
5.1.2.2.1程序启动
1 在程序启动时调用的函数名为
main
。该实现没有声明此函数的原型。它应使用int
的返回类型定义,并且没有参数:字符串
或者使用两个参数(这里称为
argc
和argv
,尽管可以使用任何名称,因为它们对于声明它们的函数是局部的):型
或等同物或以某种其它实现定义的方式。
2 如果声明了它们,则
main
函数的参数应遵守以下约束:argc
的值应为非负值。argv[argc]
应该是空指针。argc
的值大于零,则数组成员argv[0]
到argv[argc-1]
(含)应包含指向字符串的指针,它们被赋予了实现-在程序启动之前由宿主环境定义的值。目的是向程序提供在程序启动之前从宿主环境中的其他地方确定的信息。如果宿主环境不能如果提供字符串同时包含字母和小写字母,则实现应确保字符串以小写字母接收。argc
的值大于零,则argv[0]
指向的字符串表示程序名称;如果主机环境中没有程序名称,则argv[0][0]
应为空字符。如果argc
的值大于1,则argv[1]
到argv[argc-1]
指向的字符串表示程序参数。argc
和argv
以及argv
数组指向的字符串应可由程序修改,并在程序启动和程序终止之间保留其最后存储的值。因此,您不应该尝试修改
argv[1]
以使其将缺少的参数值指向argv[1] = "default"
,尽管这可能在大多数目标上都能正常工作。相反,您可以修改argv
参数本身以使其指向另一个具有正确内容的数组:型
这种方法有点非常规:一种更经典的方法是使用命名变量和默认值作为可选的命令行参数:
型
uxh89sit8#
撤销我以前的答案,在这个愚蠢的探索中,一个简单的解决方案,我相信,还没有被建议,但具体回答了OP的愿望,当命令行上没有提供时,将
argv[1]
设置为默认值。字符串
输出量:
型
没有
malloc/free
的烦恼。没有VLA。便携式。可扩展。KISS...kqlmhetl9#
您将得到由索引越界异常引起的segfault
在C中解析args时,你应该检查getopt和argp: