ChatGPT解决这个技术问题 Extra ChatGPT

int argc, char *argv[] 是什么意思?

在许多 C++ IDE 和编译器中,当它为您生成 main 函数时,它看起来像这样:

int main(int argc, char *argv[])

当我在没有 IDE 的情况下仅使用命令行编译器编写 C++ 代码时,我键入:

int main()

没有任何参数。这是什么意思,对我的计划至关重要吗?

如果您的程序将忽略命令行参数,那么您编写的内容就可以了。如果您的程序需要处理命令行参数,那么 IDE 做得对。
给黑客的提示:尝试声明 int main(int argc, char* argv[], char* envp[]) 并打印出最后一个参数。 ;)
@ulidtko,你教新手在他们的程序中引入漏洞是不好的;)
@Gab 环境变量的简单打印如何导致漏洞?只是不要将受污染的字符串逐字传递给 system() 调用、数据库查询等。像往常一样使用用户输入。
@ulidtko 有趣.. 您能否解释一下为什么在使用 char **envp 参数时不必传递受污染的字符串、数据库查询等?

u
user229044

argvargc 是命令行参数在 C 和 C++ 中传递给 main() 的方式。

argc 将是 argv 指向的字符串数。这将(实际上)是 1 加上参数的数量,因为几乎所有的实现都会将程序的名称添加到数组中。

按照约定,变量被命名为 argcargument count)和 argvargument vector),但它们可以被赋予任何有效的标识符:int main(int num_args, char** arg_strings) 等价于有效的。

如果您不打算处理命令行参数,它们也可以完全省略,产生 int main()

试试下面的程序:

#include <iostream>

int main(int argc, char** argv) {
    std::cout << "Have " << argc << " arguments:" << std::endl;
    for (int i = 0; i < argc; ++i) {
        std::cout << argv[i] << std::endl;
    }
}

./test a1 b2 c3 运行它会输出

Have 4 arguments:
./test
a1
b2
c3

我想我应该补充一下,这在大多数系统中都是一样的,尽管它们有时会被抽象化。例如,在 Pascal/Delphi/Lazarus 中,你会得到; ParamStr 和 ParamCount(如果我没记错的话)。我的观点是,当您(如果有的话)用其他语言/ose 编写本机应用程序时,很有可能上面定义了供您使用,并且它们在所有支持的系统中完全一样(计数/字符串列表)他们。
但是话又说回来,如果 argc 为 0 且 argv 为 NULL,那么肯定是 argv[argc] = *(NULL + 0) = *NULL = NULL = 0,对吧?
@EmilVikström 不,这是一个可能导致段错误的严重错误。 *NULL 绝对不等于 NULL
@EmilVikström 您可以for (char **arg = argv; *arg; arg++) { printf("\t%s\n", *arg);}我相信 for 循环中的 *arg 暗示 *arg != NULL(即当 *arg 为真时)。
@BiMo 您必须向它传递 3 个 CLI 参数才能生成该输出。请参阅命令 ./test a1 b2 c3
P
Peter Mortensen

argc 是从命令行传入程序的参数数量,argv 是参数数组。

您可以遍历参数,知道它们的数量,例如:

for(int i = 0; i < argc; i++)
{
    // argv[i] is the argument at index i
}

T
Toby Speight

假设您这样运行程序(使用 sh 语法):

myprog arg1 arg2 'arg 3'

如果您将 main 声明为 int main(int argc, char *argv[]),那么(在大多数环境中),您的 main() 将被调用,就像这样:

p = { "myprog", "arg1", "arg2", "arg 3", NULL };
exit(main(4, p));

但是,如果您将 main 声明为 int main(),它将被称为类似

exit(main());

你没有得到通过的论点。

还有两点需要注意:

这是 main 仅有的两个标准强制签名。如果特定平台接受额外的参数或不同的返回类型,那么这是一个扩展,不应该在可移植程序中依赖。 *argv[] 和 **argv 是完全等价的,所以你可以把 int main(int argc, char *argv[]) 写成 int main(int argc, char **argv)。


如果我们是技术性的,basic.start.main/2 明确允许实现定义的 main() 附加版本,前提是实现提供两个预定义版本。因此,它们并非完全不合格。最常见的是 envp,它在 C 和 C++ 中都非常有名,以至于 it's literally the very first entry in section J.5 (Common extensions) of the C standard
感谢@Justin 的漂亮迂腐。答案更新为更正确。
argv 的最后一个元素是否总是 NULL?我正在阅读一些代码,其中调用了 argv[1] 而没有检查 argc > 1,而编写代码的人显然希望具有正确的值或 NULL
@user276648,是的 - The value of argv[argc] shall be 0.
a
adrian
int main();

这是一个简单的声明。它不能接受任何命令行参数。

int main(int argc, char* argv[]);

当您的程序必须采用命令行参数时使用此声明。像这样运行时:

myprogram arg1 arg2 arg3

argc 或 Argument Count 将设置为 4(四个参数),并且 argv 或 Argument Vectors 将填充指向“myprogram”、“arg1”、“arg2”和“arg3”的字符串指针. 程序调用 (myprogram) 包含在参数中!

或者,您可以使用:

int main(int argc, char** argv);

这也是有效的。

您可以添加另一个参数:

int main (int argc, char *argv[], char *envp[])

envp 参数还包含环境变量。每个条目都遵循以下格式:

VARIABLENAME=VariableValue

像这样:

SHELL=/bin/bash    

环境变量列表以空值结尾。

重要提示:请勿在对 system() 的调用中直接使用任何 argvenvp 值!这是一个巨大的安全漏洞,因为恶意用户可以将环境变量设置为命令行命令并(可能)造成巨大的破坏。一般来说,不要使用 system()。几乎总是有通过 C 库实现的更好的解决方案。


A
Azeem

main 的参数表示程序启动时提供给程序的命令行参数。 argc 参数表示命令行参数的数量,char *argv[] 是一个字符串数组(字符指针),表示命令行上提供的各个参数。


argv[] 始终将 argv[arg] 作为空指针。并且 Argv[0] 始终是(完整路径)/executableName 作为 nul 终止的字符串
@user3629249:不一定; argv[0] 是启动 C 程序的程序给出的 argv[0]。在 Bash 的情况下,它通常(也许总是)是可执行文件的路径名,但 Bash 并不是执行其他程序的唯一程序。允许使用:char *args[] = { "cat", "/dev/null", "/etc/passwd", 0 }; execv("/bin/ls", args);,尽管有些古怪。在许多系统上,程序视为 argv[0] 的值将是 cat,即使可执行文件是 /bin/ls
A
Azeem

main 函数可以有两个参数,argcargvargc 是一个整数 (int) 参数,它是传递给程序的参数数量。

程序名称始终是第一个参数,因此程序至少有一个参数,argc 的最小值将是一个。但是如果一个程序本身有两个参数,则 argc 的值将是三个。

参数 argv 指向一个字符串数组,称为参数向量。它是函数参数的一维字符串数组。


N
Nick Gerakines

第一个参数是提供的参数数量,第二个参数是表示这些参数的字符串列表。


argv[0] 中的第一个条目是程序名称,而不是参数
@user3629249 带有程序路径的程序名称。 ;)
A
Anoop Rana

让我们考虑一下声明:

int main (int argc, char *argv[])

在上面的声明中,名为 argv 的第二个参数的类型实际上是一个 char**。也就是说,argv 是一个 指针,指向一个指向 char 的指针。这是因为由于类型衰减char* [] 衰减char**。例如,下面给出的声明是等价的:

int main (int argc, char *argv[]); //first declaration
int main (int argc, char **argv);  //RE-DECLARATION. Equivalent to the above declaration

换句话说,argv 是一个指针,它指向具有 char* 类型元素的数组的第一个元素。此外,数组的每个元素 argv[i](具有 char* 类型的元素)本身都指向一个字符,该字符是 null 终止字符串的开始。也就是说,每个元素 argv[i] 都指向数组的第一个元素,其元素类型为 char(而不是 const char)。为说明目的给出了一个图表:

https://i.stack.imgur.com/4TpCz.png

正如在其他答案中已经说过的,当我们想要使用命令行参数时,会使用这种形式的 main 声明。


C
Community

两者的

int main(int argc, char *argv[]);
int main();

是 C 或 C++ 程序入口点的合法定义。 Stroustrup: C++ Style and Technique FAQ 详细说明了您的主要功能可能或合法的一些变体。


可能想把 void 放在... int main() ==> int main(void)...为了兼容性和可读性。我不知道是否所有旧版本的 C 都允许 void 函数在声明中具有空参数列表。
@dylnmc 这不会带来任何可读性增益,并且在所有 C++ 版本中完全等效。只有在 C 中这确实有区别,但只是在声明中,而不是在定义中。
@Ruslan 抱歉,我刚刚在学习 C 时发布了此内容,并且我可能已经读过在 C 的早期版本中需要 void。不要引用我的话,我现在知道这是一个有点愚蠢的评论。不过,它不会受伤。
如果 argc<3 返回错误怎么办?可能出了什么问题?