main() 的第二个参数的 char *argv[] 和 char **argv 之间的区别 [重复]

Posted

技术标签:

【中文标题】main() 的第二个参数的 char *argv[] 和 char **argv 之间的区别 [重复]【英文标题】:Difference between char *argv[] and char **argv for the second argument to main() [duplicate] 【发布时间】:2015-01-28 14:01:06 【问题描述】:

代码 1

#include<stdio.h>

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

int j;
printf("%d", argv[1][0]);
return 0;

代码 2

#include<stdio.h>

int main(int argc, char **argv)

int j;
printf("%d", argv[1][0]);
return 0;

CODE 1 和 CODE 2 都给出相同的输出。但是CODE 1和CODE 2中main函数的argument 2是不同的。指针数组在编译时在数据部分上方创建。 argv 是指针数组。然后我们应该在主函数中将参数声明为指向字符的指针,即**argv。在 CODE 1 中声明如何正确?

【问题讨论】:

就编译器而言,第二个参数没有任何不同,即char *argv[] 仅相当于char **argv。这更像是首选编码风格的问题。 【参考方案1】:

char** xchar* x[] 是表达同一事物的两种方式,这对 c 来说很重要。两者都声明参数接收指向指针数组的指针。回想一下,你总是可以写:

 char *parray[100];
 char **x;

 x = &parray[0];

然后同样使用 x。

【讨论】:

除了使用sizeof IMO,如果您至少简要地指出 C 中有几个地方(如 Ed Heal 提到的 sizeof)数组不是 i> 等价于指针,并且函数参数声明(问题询问)中的“数组调整”与表达式中的“数组衰减”不同(尽管相关)。对于参考,您可以引用例如What's a modern term for “array/pointer equivalence”? 和 Exception to array not decaying into a pointer? @Ilmari-Karonen 恕我直言,这个答案是正确的(但是这个例子是错误的)。仅仅因为函数签名中有大括号并不意味着它将是一个数组变量!事实是,C 假定它是一个普通的指针!这甚至是人们可以从 C 中得到的唯一合乎逻辑的决定,因为如果真的假设一个数组变量,就没有什么可以分配给它(数组变量没有像指针那样特定于自身的单独内存)。所以我相信这只是 C 提供的一种简化表示法(chararr[]),它与其他表示法(char*arr)完全相同。【参考方案2】:

基本上,char* argv[] 表示 char 指针数组,而 char** argv 表示指向 char 指针的指针。

在任何数组中,数组名都是指向数组第一个元素的指针,即包含第一个元素的地址。

所以在下面给出的代码中,在 char 数组 x 中,x 是指向第一个元素 '1' 的指针,它是一个字符。所以它是一个字符的指针。

在数组 arr 中,arr 是指针第一个元素 x,它本身就是一个指向字符的指针。所以它是一个指向另一个指针的指针。

因此,x 是 char*,arr 是 char**。

在函数中接收东西时,基本规则是,你必须告诉你正在接收的东西的类型。所以要么你简单地说你想接收一个 char**,要么你也可以说 char* arr[]。

在第一种情况下,我们不需要考虑任何复杂的事情。我们只知道,我们正在接收一个 char* 数组。我们不知道吗?所以,我们收到并使用它。

在第二种情况下,它很简单,正如我在上面解释的 arr 是一个 char**,你可以把它作为它的类型并安全地接收它。现在系统知道我们收到的东西的类型,我们可以通过简单地使用数组注释来访问下一个元素。就像,我们已经收到了数组的起始地址,我们肯定可以进入下一个元素,并且我们知道它的类型,我们知道它包含什么以及如何进一步使用它。我们知道它包含指向 char 的指针,因此我们也可以合法地访问它们。

void func1(char* arr[])

    //function body

void func2(char** arr)

    //function body


int main()

    //x, y and z are pointer to char
    char x[3]='1', '2', '3';
    char y[3]='4', '5', '6';
    char z[3]='7', '8', '9';

    //arr is pointer to char pointer
    char* arr[3]=x, y, z;

    func1(arr);
    func2(arr);

【讨论】:

这个答案有很多误解,已经把at least one person弄糊涂了。首先,char* argv[]char** argv 是绝对等价的,根本没有不同的意思。其次,arr不是指针。我没有仔细研究文本以找出其他具体问题,但这些问题已经很严重了,值得一票否决,并真诚地希望你能在其他人被误导之前重新审视这篇文章! (至少在这种情况下完全等效 @LightnessRacesinOrbit 回复:Secondly, arr is not a pointer - 或许评论一下 arr 是什么,arr 是什么 - 我在这个答案中看到了各种用途。 @chux:好点。我在回复代码评论,忘记说了! 我同意这个答案具有误导性!一方面,数组名不是指针!它是数组第一个元素的“地址”,它不包含它!因为它在内存中没有单独的位置!请更正这些错误或删除答案。【参考方案3】:

它们完全一样。 C11 标准第 5.1.2.2.2 条规定:

程序启动时调用的函数名为main。这 实现没有声明这个函数的原型。应该是 使用int 的返回类型定义并且没有参数:

int main(void)  /* ... */ 

或带有两个参数(这里称为argcargv,不过 可以使用任何名称,因为它们对于它们所在的函数是本地的 已声明):

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

或等价物;10) 或在其他一些实现中定义的 方式。

10) 因此,int 可以替换为定义为 int 的 typedef 名称,或者 argv的类型可以写成char ** argv,以此类推。

显然,这两个声明的意图是相同的。最重要的是,该规则在 §6.7.6.3/7 中进行了描述:

应调整参数声明为“类型的数组” to ''限定指针 type'',其中类型限定符(如果有)是在数组类型派生的 [] 中指定的限定符。 ...

【讨论】:

【参考方案4】:

[编辑] 在评论时使用 GCC 可能是 GCC 7.2

像这样声明一个数组

char array[]

将其设为 const,这意味着您不能拥有以下代码

char array[] = "hello";
array = "hey";

即使第二个字符串更小并且应该适合您也会收到此错误

错误:数组类型“char [6]”不可赋值

如果你有**argv你可以写

main(int argc, char **argv)

    char **other_array;
    /*
     * do stuff with other_array
     */
    argv = other_array;

如果你有*argv[] 那么

main(int argc, char *argv[])

    char **other_array;
    /*
     * do stuff with other_array
     */
    argv = other_array;

给你这个警告

警告:从 'char **' 分配给 'const char **' 会丢弃嵌套指针类型中的限定符

所以从技术上讲,这是一个小的优化,就好像你写了const

【讨论】:

什么?!肯定不是,这是哪个编译器? 它是 3 1/2 年前,我假设 gcc 7,它肯定不是 gcc 10

以上是关于main() 的第二个参数的 char *argv[] 和 char **argv 之间的区别 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

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

main函数

main(argc, char *argv[])

main(argc,argv[])

c语言如何获得文件当前路径?

C的指针疑惑:C和指针13(高级指针话题)