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

Gre*_*ven 476 c++ parameters argv command-line-arguments argc

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

int main(int argc, char *argv[])
Run Code Online (Sandbox Code Playgroud)

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

int main()
Run Code Online (Sandbox Code Playgroud)

没有任何参数.这意味着什么,对我的计划至关重要?

mea*_*gar 615

argv以及argc如何main()在C和C++ 中传递命令行参数.

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

变量按约定命名argc(参数计数)和argv(参数矢量),但它们可以被赋予任何有效的标识符: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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Have 4 arguments:
./test
a1
b2
c3
Run Code Online (Sandbox Code Playgroud)

  • @Chuck:由于"`argv [argc]`的值应为0"(C++03§3.6.1/ 2),`argv`不能为空. (72认同)
  • @Chuck:C(至少C99)有相同的要求. (19认同)
  • `argc`可以是0,在这种情况下`argv`可以是NULL.这是标准的AFAIK所允许的.我从来没有听说过在实践中这样做的系统,但它肯定存在并且不会违反任何标准. (8认同)
  • @EmilVikström不,这是一个严重的错误,可能导致段错误.`*NULL`绝对不等于`NULL`. (8认同)
  • 我想我应该补充一点,这在大多数系统中都是一样的,尽管它们已被抽象一些.例如,在Pascal/Delphi/Lazarus中,你会得到; ParamStr和ParamCount(如果记忆对我有用).我的观点是,当你(如果有的话)用其他语言/ ose写本机应用程序时,很有可能为你定义上面的内容,并且它们在所有支持的系统中完全相同(计数/字符串列表)他们. (2认同)

Joh*_*ker 50

argc是从命令行传递到程序中的参数数量,是参数argv数组.

你可以通过参数循环知道它们的数量,如:

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


Tob*_*ght 18

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

myprog arg1 arg2 'arg 3'
Run Code Online (Sandbox Code Playgroud)

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

p = { "myprog", "arg1", "arg2", "arg 3", NULL };
exit(main(4, p));
Run Code Online (Sandbox Code Playgroud)

但是,如果你将main声明为int main(),它将被称为类似的东西

exit(main());
Run Code Online (Sandbox Code Playgroud)

并且你没有得到传递的参数.

还有两点需要注意:

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

  • 如果我们是技术人员,[`basic.start.main/2`](https://timsong-cpp.github.io/cppwp/basic.start.main#2)明确允许实现定义的附加版本` main()`,前提是该实现提供了两个预定义版本.所以,他们并非_exactly_不符合.最常见的是`envp`,它在C和C++中都是众所周知的[它实际上是C标准第J.5节(通用扩展)中的第一个条目](http://port70.net /~nsz/c/c11/n1570.html#J.5). (2认同)
  • @user276648,是的 - [“argv[argc]”的值应为“0”。](https://eel.is/c++draft/basic.start.main#2.2) (2认同)

use*_*570 14

让我们考虑一下声明:

int main (int argc, char *argv[])
Run Code Online (Sandbox Code Playgroud)

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

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

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

argv 和 argc

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


Blu*_*kMN 8

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

  • @ 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`. (3认同)
  • Argv []总是将argv [arg]作为空指针.和Argv [0]始终是(完整路径)/ executableName作为一个空终止字符串 (2认同)

小智 5

main函数可以有两个参数,argcargv.argc是一个integer(int)参数,它是传递给程序的参数数量.

程序名始终是第一个参数,因此程序中至少有一个参数,最小值argc为1.但是如果一个程序本身有两个参数,那么它的值argc将是三.

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


Adr*_*ang 5

int main();
Run Code Online (Sandbox Code Playgroud)

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

int main(int argc, char* argv[]);
Run Code Online (Sandbox Code Playgroud)

当您的程序必须接受命令行参数时,将使用此声明。当这样运行时:

myprogram arg1 arg2 arg3
Run Code Online (Sandbox Code Playgroud)

argc或参数计数设置为4(四个参数),而argv参数或参数向量将填充指向“ myprogram”,“ arg1”,“ arg2”和“ arg3”的字符串指针。程序调用(myprogram)包含在参数中!

或者,您可以使用:

int main(int argc, char** argv);
Run Code Online (Sandbox Code Playgroud)

这也是有效的。

您可以添加另一个参数:

int main (int argc, char *argv[], char *envp[])
Run Code Online (Sandbox Code Playgroud)

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

VARIABLENAME=VariableValue
Run Code Online (Sandbox Code Playgroud)

像这样:

SHELL=/bin/bash    
Run Code Online (Sandbox Code Playgroud)

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

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


gar*_*chy 5

命令行参数: main( int argc, char * argv[] )

\n

在 Unix 中,当您将附加参数传递给命令时,这些命令必须传递给执行进程。例如,在调用 中ls -al,它执行程序ls并将字符串-al作为参数传递:

\n
% ls\ncontent.html  index.html  primary.0.html\n% ls -al\ntotal 20\ndrwxr-xr-x 2 dwharder users 4096 Sep 11 16:38 .\ndrwxr-xr-x 6 dwharder users 4096 Sep 11 16:35 ..\n-rwxr-xr-x 1 dwharder users  117 Sep 11 16:38 content.html\n-rwxr-xr-x 1 dwharder users 1400 Sep 11 16:37 index.html\n-rwxr-xr-x 1 dwharder users  532 Sep 11 16:38 primary.0.html\n%\n
Run Code Online (Sandbox Code Playgroud)\n

正在运行的程序访问这些附加参数的方式是将它们作为参数传递给函数 main:

\n
int main( int argc, char *argv[] ) {\n
Run Code Online (Sandbox Code Playgroud)\n

这里的argc意思是参数计数,argv意思是参数向量。

\n

第一个参数是传递的参数数量加上一个,以包含为使这些进程运行而执行的程序的名称。因此,argc始终大于零,并且argv[0]是为开始此过程而运行的可执行文件的名称(包括路径)。例如,如果我们运行

\n
#include <stdio.h>\n\nint main( int argc, char *argv[] ) {\n        printf( "argv[0]:  %s\\n", argv[0] );\n\n        return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在这里,我们编译此代码并首先编译并运行它,以便可执行文件名称为a.out,然后我们再次编译并运行它,以便可执行文件名称为arg

\n
% gcc argument.0.c\n% ./a.out \nargv[0]:  ./a.out\n% gcc -o arg argument.0.c\n% ./arg \nargv[0]:  ./arg\n%\n
Run Code Online (Sandbox Code Playgroud)\n

如果传递更多额外的命令行参数,则所有字符的字符串将根据一些规则被解析并分成子字符串;但是,如果所有字符都是字符、数字或空格,则 shell 会根据空格分隔这些字符,并分配args[1]第一个字符的地址、args[2]第二个字符的地址,依此类推。

\n

以下程序打印所有参数:

\n
#include <stdio.h>\n\nint main( int argc, char *argv[] ) {\n        int i;\n\n        printf( "argc:     %d\\n", argc );\n        printf( "argv[0]:  %s\\n", argv[0] );\n\n        if ( argc == 1 ) {\n                printf( "No arguments were passed.\\n" );\n        } else {\n                printf( "Arguments:\\n" );\n\n                for ( i = 1; i < argc; ++i ) {\n                        printf( "  %d. %s\\n", i, argv[i] );\n                }\n        }\n\n        return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在这里,我们使用 1 个然后 12 个命令行参数执行该程序:

\n
% gcc argument.c\n% ./a.out first\nargc:     2\nargv[0]:  ./a.out\nArguments:\n  1. first\n% ./a.out first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth\nargc:     13\nargv[0]:  ./a.out\nArguments:\n  1. first\n  2. second\n  3. third\n  4. fourth\n  5. fifth\n  6. sixth\n  7. seventh\n  8. eighth\n  9. ninth\n  10. tenth\n  11. eleventh\n  12. twelfth\n% \n
Run Code Online (Sandbox Code Playgroud)\n

为了娱乐

\n

现在,您可能想知道实际发生了什么(如果您不知道,欢迎您跳过这一点)。首先,当执行命令时,shell 解析命令行并用空字符分隔各个部分\\0。例如,执行

\n
% ./a.out first second third fourth fifth\n
Run Code Online (Sandbox Code Playgroud)\n

让 shell 生成字符串./a.out\xe2\x98\x90first\xe2\x98\x90second\xe2\x98\x90third\xe2\x98\x90fourth\xe2\x98\x90fifth\xe2\x98\x90,其中框代表空字符。接下来,为六个 ( argc) 指针的数组分配内存,并将这六个指针分配给命令行解析到的每个字符串的第一个字符。最后,为堆栈分配内存,并使用 8 字节对齐,将两个参数放入堆栈中。如图 1 所示。

\n

在命令行调用./a.outfirst Second Third Fourth Fifth的结果

\n

./a.out first second third fourth fifth图 1.命令行调用的结果。

\n

进一步的乐趣

\n

在 Unix 中,shell 对命令进行进一步处理。例如,如果它发现指示当前目录中的文件的通配符,它​​将尝试扩展这些通配符。其中包括?一个未知字符和*任意数量的字符。

\n

例如,以下命令检查当前目录中的文件:

\n
% ls\na.out  argument.0.c  argument.1.c  content.html  images  index.html  primary.0.html  src\n% ./a.out *\nargc:     9\nargv[0]:  ./a.out\nArguments:\n  1. a.out\n  2. argument.0.c\n  3. argument.1.c\n  4. content.html\n  5. images\n  6. index.html\n  7. primary.0.html\n  8. src\n% ./a.out *.html\nargc:     4\nargv[0]:  ./a.out\nArguments:\n  1. content.html\n  2. index.html\n  3. primary.0.html\n% ./a.out argument.?.c\nargc:     3\nargv[0]:  ./a.out\nArguments:\n  1. argument.0.c\n  2. argument.1.c\n
Run Code Online (Sandbox Code Playgroud)\n

同样,您可以告诉命令行将空格视为一个字符串的一部分,或者通过在空格或通配符之前使用反斜杠或用单引号或双引号将字符串括起来来忽略通配符。

\n
% ./a.out hi\\ there\\?\nargc:     2\nargv[0]:  ./a.out\nArguments:\n  1. hi there?\n% ./a.out "hi there?"\nargc:     2\nargv[0]:  ./a.out\nArguments:\n  1. hi there?\n% ./a.out \'hi there?\'\nargc:     2\nargv[0]:  ./a.out\nArguments:\n  1. hi there?\n%\n
Run Code Online (Sandbox Code Playgroud)\n

最后,如果您用反引号包围文本,它将首先执行该文本,然后将其替换为命令的输出:

\n
% ./a.out `ls *.c`\nargc:     4\nargv[0]:  ./a.out\nArguments:\n  2. argument.0.c\n  3. argument.1.c\n%\n
Run Code Online (Sandbox Code Playgroud)\n

猜猜如果你输入会发生什么./a.out ls -al

\n

免责声明:以上帖子直接取自https://ece.uwaterloo.ca/~dwharder/icsrts/C/05/。它最初是由滑铁卢大学的道格拉斯·威廉·哈德 (Douglas Wilhelm Harder)编写的。如果它完全属于另一个人,那我为什么要把它放在这里?因为我读了他的文章,学到了新东西,我非常喜欢它,所以我把它放在这里,以便其他人也能从中受益。再说一次,所有的努力和掌声都属于哈德先生,而不是我。谢谢。

\n

  • 感谢您分享这个。这是一个很好的答案! (2认同)