Type** name和Type* name[]有什么区别?

9

“Type** name”和“Type* name[]”有什么区别?

为什么有人会使用其中的一个而不是另一个呢?

谢谢。


实际上没有区别。例如,在C程序中,我们总是看到char **argv和char *argv[]可以互换使用来声明main函数的参数。您可能会因为清晰度或一致性的原因而选择其中之一。 - Pete Wilson
4个回答

13

那得看它是在变量声明中还是函数参数中了。如果是在变量声明中:

Type** name = &pointer_to_type;
Type* name[] = { &pointer_to_type, 0, &pointer_to_type };
第一个是指向指针类型的指针,而第二个是长度为3的指向类型的指针数组。
如果在函数参数中使用,它们是相同的。数组会衰减为指针,Type** nameType* name[]在函数参数中完全相同。但是,第二种形式明确表示name是一个长度未知的指针数组,而第一种形式则不表示。我会使用Type**来指定单个元素,Type*[]来指定数组。

1
我害怕你,小马。已经加入了32天并获得了6000的声望。这是什么技巧? - sidyll
2
想补充一下关于内存分配的内容:使用Type* name[]作为变量声明会在第一次解引用时自动获得有效的内存(指针数组在堆栈上布局)。您可以按顺序使用以下命令:Type* name[4]; name[3] = NULL;但是,如果您尝试使用Type** name进行此操作,除非手动将其指向有效的Type*,否则会导致segfault。 - Xavier Holt
2
@sidyll:我猜是热情?我甚至有一个徽章:P - K-ballo
好的,我还拥有一个“狂热者”徽章 :-) 无论如何,恭喜你在准确回答方面付出的努力和天赋。 - sidyll
K-Ballo:为什么你不给赏金?? - Matt Joiner
1
@sidyll,谢谢你让我笑了... 我也忍不住注意到那只小马着火了。@K,这是另一个徽章给你! - Eran

4

这两种类型的主要区别体现在声明/定义对象时。

Type *name[] 表示创建一个大小未知的数组(可以从初始化器中推断出大小),Type** name则表示创建一个指针。也就是说:

char *array[]={"hello", "world", 0}; /* OK, array of size 3 */
char **ptr={"hello", "world", 0};    /* not possible */

它们在某些表达式中的行为不同。特别地,数组是不能被赋值的,但指针变量可以:

ptr++, ptr=array; /* assignment and mutation of ptr possible */
// array=whatever /* impossible */

sizeof运算符在这两个上的工作方式不同。sizeof(array)将取决于数组的元素数(在这种情况下可能为12),但sizeof(ptr)始终返回相同的大小(例如,在主要的32位体系结构上为4)。

此外,在声明全局变量时,您不能混用这两个:

extern char* data[];

必须在 .c 文件中附带以下内容:

char* data[N];

相反也是一样的。基本上,定义数组意味着分配几个连续的对象,而定义指针意味着分配一个单独的变量。编译器对两者的处理不同,并且必须知道哪一个是哪一个。

然而,在声明或传递参数到函数时,它们是相同的。所以

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

“_数组不是lvalue_”这种说法是错误的。实际上,它们是lvalue。"因此它们不能被赋值"也是不正确的。即使这样做也没有意义:(x不是lvalue)并不意味着("x = whatever;"是非法的)。C++并不是一门简单的语言。 ;) - curiousguy

1

取决于上下文。

如果它定义的是不是函数参数的变量,则在 Type** name 中,name 是指向类型为 Type 的变量的指针的指针,而在 Type* name[SOME_POSITIVE_INTEGER_CONSTANT] 中,它是类型为 Type 的变量指针的数组。

如果它是函数参数,则两者相同,并且 name 是指向类型为 Type 的变量的指针的指针。


在一个变量的声明中,如果它不是定义,你可以省略 SOME_POSITIVE_INTEGER_CONSTANT - curiousguy
@curiousguy:在文件作用域中,“int* ga[];”会导致“警告:假定数组ga'只有一个元素”。而在函数作用域中,“int* ma[];”会导致“错误:在ma'中缺少数组大小”。你应该避免这种情况。然而,“extern int* ega[];”是可以的。这是使用启用了所有警告的gcc(3.3.4)编译的C代码。 - Alexey Frunze
没有所谓的“文件作用域”。你可能指的是全局作用域。在任何作用域中,没有存储类限定符extern的变量声明也是一个定义 - curiousguy

0

基本上,Type** 是指向指针的指针。可以像 (Type*)* 这样考虑。因此它指向可以是 Type 或 Type[] 的 Type*。

另一方面,Type* 是指向 Type 或在这种情况下,数组 Type[] 的指针。因此它们 '几乎' 相同。


请不要把它看作是(Type*)*!语法不是这样的。把它看作是Type *(*),或者更确切地说是Type (*(*name)):表达式(*(*name))的类型是Type。(但对于引用或函数则不适用。) - curiousguy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接