C ++ – char ** argv与char * argv
char** argv
和char* argv[]
什么区别? 在int main(int argc, char** argv)
和int main(int argc, char* argv[])
?
他们是一样的吗? 特别是第一部分没有[]
。
他们完全相同。 char *argv[]
必须被读为指向char
的指针数组,并且数组参数被降级为指针,所以指向指向char
或char **
指针。
这在C中是一样的。
他们确实是一模一样的。
数组要记住的黄金法则是:
“数组的名称是指向数组的第一个元素的指针”。
所以如果你声明如下:
char text[] = "A string of characters.";
然后,variables“text”是一个指向刚刚声明的字符数组中第一个字符的指针。 换句话说,“文本”是char *
types的。 当你使用[ index ]访问一个数组的元素时,你实际上做的是将索引的偏移量添加到指向数组第一个元素的指针,然后解引用这个新的指针。 以下两行将因此将两个variables初始化为't':
char thirdChar = string[3]; char thirdChar2 = *(string+3);
使用方括号是语言提供的便利,使代码更加可读。 但是,当你开始考虑更复杂的事情时,这种方式非常重要,例如指向指针的指针。 char** argv
与char* argv[]
相同,因为在第二种情况下,“数组的名称是指向数组中第一个元素的指针 ”。
从这里你也应该能够明白为什么数组索引是从0开始的。指向第一个元素的指针是数组的variables名(再次是黄金法则)加上偏移量…什么都不是!
我和我的一个朋友进行过辩论,哪个更适合在这里使用。 使用char* argv[]
符号,读者可能会更清楚地知道,这实际上是一个“指向字符的指针数组”,而不是char** argv
表示法,它可以被读为“指向指向字符”。 我的看法是,后面的这个表示法并没有向读者传达太多的信息。
很高兴知道它们完全一样,但为了可读性,我认为如果意图是一个指针数组,那么char* argv[]
表示法就更清楚地expression了这一点。
为了所有的实际目的,他们是一样的。 这是由于C / C ++对作为parameter passing的数组的处理,在这种情况下,一个数组衰减到一个指针。
对于问题的第一部分:
- char ** argv:指向char的指针
- char * argv []:指向数组的指针
所以问题是一个typesC和一个数组C []的指针是否是相同的东西。 它们一般都不是,但是在签名中使用它们是等价的 。
换句话说,在你的例子中没有什么区别,但是要牢记指针和数组之间的区别是很重要的。
括号forms仅在语句声明中有用,如:
char *a[] = {"foo", "bar", "baz"}; printf("%d\n", sizeof a / sizeof *a); // prints 3
因为它在编译时知道数组的大小。 当你将一个括号forms作为parameter passing给一个函数(main或者其他函数)时,编译器不知道在运行时数组的大小是多less,所以它和char ** a完全一样。 我更喜欢char ** argv,因为它更清晰,sizeof不会像在声明声明表单上那样工作。
在C和C ++中, TYPE * NAME
和TYPE NAME[]
都有区别。 在C ++中,这两种types都不可互换。 例如下面的函数在C ++中是非法的(你会得到一个错误),但在C中是合法的(你会得到警告):
int some (int *a[3]) // a is array of dimension 3 of pointers to int { return sizeof a; } int main () { int x[3][3]; std::cout << some(x)<< std::endl; return 0; }
为了使其合法,只需将签名更改为int some (int (*a)[3])
(指向3个int的数组的指针)或int some (int a[][3])
。 最后方括号中的数字必须等于参数的数字。 从数组数组转换为指针数组是非法的。 从指针转换为指向数组数组也是非法的。 但是将指针转换为指针数组是合法的!
所以记住: 只有最接近于解引用types签名并不重要,其他人也可以 (在指针和数组的上下文中)。
考虑我们有一个指向int指针的指针:
int ** a; &a -> a -> *a -> **a (1) (2) (3) (4)
- 你不能改变这个值,types是
int ***
。 可以通过函数作为int **b[]
或int ***b
。 最好的是int *** const b
。 - types是
int **
。 可能被函数作为int *b[]
或int ** b
。 数组声明的括号可以是空的或包含任何数字。 - 该types是
int *
。 可能被函数作为int b[]
或int * b
甚至void * b
- 应该作为int参数。 我不想陷入细节,就像隐式的构造函数调用一样。
回答你的问题: 主函数中argumets的真实types是char ** argv
,所以它可以很容易地表示为char *argv[]
(但不是char (*argv)[]
)。 主函数的argv
名也可以安全地改变。 你可以很容易地检查: std::cout << typeid(argv).name();
(PPc =指向p的指针)
顺便说一句:有一个很酷的function,传递数组作为参考:
void somef(int (&arr)[3]) { printf("%i", (sizeof arr)/(sizeof(int))); // will print 3! }
而且,指向任何东西的指针都可以被函数隐式地接受(转换)为空指针。 但是只有单个指针(不是指针指针等)。
进一步阅读:
- Bjarne Stroustrup,C ++,第7.4章
- C指针FAQ
除了以下细微的区别之外,两者都是一样的:
- Sizeof会给两个不同的结果
- 第二个可能不会被重新分配到新的内存区域,因为它是一个数组
- 第二个你可以只使用那些有效的索引。 如果您尝试使用超出数组长度的数组索引,则C / C ++未指定它。 然而,用char **,你可以使用从0到…的任何索引
- 第二种forms只能用作函数的forms参数。 虽然第一个甚至可以用来声明栈中的variables。