“Type** name”和“Type* name[]”有什么区别?
为什么有人会使用其中的一个而不是另一个呢?
谢谢。
那得看它是在变量声明中还是函数参数中了。如果是在变量声明中:
Type** name = &pointer_to_type;
Type* name[] = { &pointer_to_type, 0, &pointer_to_type };
第一个是指向指针类型的指针,而第二个是长度为3的指向类型的指针数组。Type** name
和Type* name[]
在函数参数中完全相同。但是,第二种形式明确表示name是一个长度未知的指针数组,而第一种形式则不表示。我会使用Type**
来指定单个元素,Type*[]
来指定数组。Type* name[]
作为变量声明会在第一次解引用时自动获得有效的内存(指针数组在堆栈上布局)。您可以按顺序使用以下命令:Type* name[4]; name[3] = NULL;
但是,如果您尝试使用Type** name
进行此操作,除非手动将其指向有效的Type*
,否则会导致segfault。 - Xavier Holt这两种类型的主要区别体现在声明/定义对象时。
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 */
取决于上下文。
如果它定义的是不是函数参数的变量,则在 Type** name
中,name
是指向类型为 Type
的变量的指针的指针,而在 Type* name[SOME_POSITIVE_INTEGER_CONSTANT]
中,它是类型为 Type
的变量指针的数组。
如果它是函数参数,则两者相同,并且 name
是指向类型为 Type
的变量的指针的指针。
SOME_POSITIVE_INTEGER_CONSTANT
。 - curiousguyga'只有一个元素”。而在函数作用域中,“int* ma[];”会导致“错误:在
ma'中缺少数组大小”。你应该避免这种情况。然而,“extern int* ega[];”是可以的。这是使用启用了所有警告的gcc(3.3.4)编译的C代码。 - Alexey Frunzeextern
的变量声明也是一个定义。 - curiousguy基本上,Type** 是指向指针的指针。可以像 (Type*)* 这样考虑。因此它指向可以是 Type 或 Type[] 的 Type*。
另一方面,Type* 是指向 Type 或在这种情况下,数组 Type[] 的指针。因此它们 '几乎' 相同。
(Type*)*
!语法不是这样的。把它看作是Type *(*)
,或者更确切地说是Type (*(*name))
:表达式(*(*name))
的类型是Type
。(但对于引用或函数则不适用。) - curiousguy