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** x
和 char* 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) /* ... */
或带有两个参数(这里称为
argc
和argv
,不过 可以使用任何名称,因为它们对于它们所在的函数是本地的 已声明):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 之间的区别 [重复]的主要内容,如果未能解决你的问题,请参考以下文章