char** argv
和char* argv[]
之间有什么区别?在int main(int argc, char** argv)
和int main(int argc, char* argv[])
?
它们是一样的吗?特别是第一部分没有[]
。
答案 0 :(得分:53)
它们完全等同。必须将char *argv[]
读作指向char
的指针数组,并将数组参数降级为指针,因此指针指向char
或char **
。
C中的情况相同。
答案 1 :(得分:23)
他们确实完全一样。
要记住的数组的黄金法则是:
“数组的名称是指向数组第一个元素的指针。”
因此,如果您声明以下内容:
char text[] = "A string of characters.";
然后变量“text”是指向你刚刚声明的字符数组中第一个字符的指针。换句话说,“text”的类型为char *
。当您使用[ index ]访问数组的元素时,您实际在做的是将 index 的偏移量添加到指向数组的第一个元素的指针,然后解除引用这个新指针。因此,以下两行将两个变量初始化为't':
char thirdChar = text[3];
char thirdChar2 = *(text+3);
使用方括号是一种由语言提供的便利性,使代码更具可读性。但是当你开始考虑更复杂的事情时,例如指针指针,这种方法非常重要。 char** argv
与char* argv[]
相同,因为在第二种情况下,“数组的名称是指针到数组中的第一个元素”。
从这里你也应该能够看到为什么数组索引从0开始。指向第一个元素的指针是数组的变量名(再次是黄金法则)加上偏移量......没有!
我和我的一个朋友讨论过哪个更好用。使用char* argv[]
符号,读者可能会更清楚这实际上是一个“字符指针数组”而不是char** argv
符号,它可以被读作“指向指针的指针”一个人物”。我的观点是,后一种符号并没有向读者传达那么多信息。
很高兴知道它们完全一样,但是为了可读性,我认为如果意图是一个指针数组,那么char* argv[]
符号可以更清楚地传达这一点。
答案 2 :(得分:3)
出于所有实际目的,它们是相同的。这是由于C / C ++对作为参数传递的数组的处理,其中数组衰减为指针。
答案 3 :(得分:3)
问题的第一部分:
所以问题是指向类型C和数组C []的指针是否相同。它们一般都不是,但它们是equivalent when used in signatures。
换句话说,你的例子没有区别,但重要的是要记住指针和数组之间的区别。
答案 4 :(得分:2)
括号形式仅在语句声明中有用,如:
char *a[] = {"foo", "bar", "baz"};
printf("%d\n", sizeof a / sizeof *a);
// prints 3
因为它在编译时知道数组的大小。将括号形式作为参数传递给函数(main或其他函数)时,编译器不知道数组在运行时的大小,因此它与char ** a完全相同。我更喜欢char ** argv,因为更清楚的是sizeof不会像声明声明表那样工作。
答案 5 :(得分:-1)
C和C ++中TYPE * NAME
和TYPE NAME[]
之间存在差异。在C ++中,这两种类型都不可交叉。例如,以下函数在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 some (int a[][3])
。最后一个方括号中的数字必须等于一个参数。从数组数组转换为指针数组是非法的。从指针转换为指针到数组数组也是非法的。但是将指针转换为指向指针数组的指针是合法的!
所以请记住:最接近解除引用类型签名无关紧要,其他人(在指针和数组的上下文中,确实如此)。
考虑我们有一个as指针指向int:
int ** a;
&a -> a -> *a -> **a
(1) (2) (3) (4)
int ***
。可以按int **b[]
或int ***b
的功能使用。最好的是int *** const b
。int **
。可以按int *b[]
或int ** b
的功能使用。数组声明的括号可以留空或包含任何数字。int *
。可以通过int b[]
或int * b
或甚至void * b
回答您的问题:主要功能中的实际类型是char ** argv
,因此可以很容易地表示为char *argv[]
(但是不是char (*argv)[]
)。此外,argv
主要功能的名称可能会safely更改。
您可以轻松检查:std::cout << typeid(argv).name();
(PPc =指向p。指向char的指针)
顺便说一句:有一个很酷的功能,将数组作为引用传递:
void somef(int (&arr)[3])
{
printf("%i", (sizeof arr)/(sizeof(int))); // will print 3!
}
此外指向任何事物的指针可能被函数隐式接受(转换)为void指针。但只有单个指针(不是指针指针等)。
进一步阅读:
答案 6 :(得分:-2)
除了以下细微差别外,两者的用法相同: