2010-02-21 81 views
4

对于指针,我对使用char **或char *或* array的声明和函数参数感到困惑[ n]等。如果一个函数接受一个(* array [n])参数,我会传递一个**类型吗?C/C++中的指针/数组语法(char ** p,* p [n])

我尝试使用左右规则并知道p是指向char(char ** p)的指针的指针,p是n个指针(* p [n])的数组,但有人说* p [n]和** p基本上是等价的。真的吗?

回答

5

阅读C宣言(这是与*和[]变量的一部分)是相当细微的。有一些网站与提示:

一个char**是一个指向(可能是多个)指针(S)到(可能是多个)字符(S)。例如,它可能是一个指向字符串指针的指针,或者是一个指向字符串指针数组的指针。

A char*[]是指向char的指针数组。当你有一个把它作为参数的函数时,C编译器会将它“衰减”为char**。这只发生在第一层...因此,举一个复杂的例子,char*[4][]变成char*(*)[4]。阅读上面的链接,以便了解这意味着什么。

或者你可以做一个(非常合理的)事情,并做一堆typedefs。我不这样做,但直到你擅长阅读宣告者,这是一个好主意。

typedef char * stringp; 
void func(stringp array[]) { ... } 
static stringp FOUR_STRINGS[4] = { ... }; 
+0

此外,如果您不是唯一阅读代码的人,那么额外的typedef对其他人的理智也是有益的 - 但当然,不要过分地把它当作相关信息的混乱和分裂(必须结合来自信息源中许多地方的信息来解码一个结构的含义)也是可读性。 – Steve314 2010-02-21 09:26:27

0

如果n==0那么它们引用相同的内存。数组索引基本上是一个指针加偏移量。 *(p[n])将与**(p+n)相同。你可以亲眼看到C中的这个简单,因为array[4]4[array]会给你同样的东西。

8

在正确的上下文(即,参数的函数),则下面的声明是等价的:

int main(int argc, char *argv[]); 
int main(int argc, char **argv); 
int main(int argc, char *argv[12]); // Very aconventional! 

类似的注释适用于函数定义(其具有嵌段包含在括号中分号的地方)。

在任何其他情况下,符号之间存在重要差异。例如:

extern char *list1[]; 
extern char **list2; 
extern char *list3[12]; 

第一个表示某处存在一个包含'char *'值的不确定大小的数组。第二个说某处 - 可能在这里 - 有一个包含指向字符指针的值的单个值。第三个人说,在某个地方 - 可能在这里 - 有12个字符指针的数组。

但是,所有三个列表都可以以相同的方式引用 - 假设它们实际上已经被定义和初始化。

list1[0][0] = '1'; 
list2[0][0] = '2'; 
list3[0][0] = '3'; 

此外,如果将它们传递到这样的功能:

function(list1, list2, list3); 

则该函数可以声明为:

void function(char **list1, char **list2, char **list3); 

的阵列(list1的,项目list3)从衰减该数组指向数组的第一个元素;当然,list2已经是一个指向指针的指针了。

void otherfunction(char *list[12]) 
{ 
    ... 
} 

的C编译器不把该声明的任何不同于:

void otherfunction(char **list) 
{ 
    ... 
} 

void otherfunction(char *list[]) 
{ 
    ... 
} 

特别

一个详细的功能,如注意,它没有进行数组边界检查,就功能而言,12也可能不存在。


C99引入VLA(可变长度数组)类型,并且还引入了“静态”和在阵列边界的尺寸的符号。您需要阅读标准以充分理解这些标准。

只需在下面的函数中说数组的大小确实很重要,并且在运行时确定。通常情况下,二维数组除了第一个维外需要指定所有维。

void vla_function(size_t m, int vla[m][m]); 

从标准引用(节6.7.5.3):

void f(double (* restrict a)[5]); 
void f(double a[restrict][5]); 
void f(double a[restrict 3][5]); 
void f(double a[restrict static 3][5]); 

(注意最后声明还指定对应于在至f的任何呼叫的参数必须是 非空指针指向至少三个数组中的第一个至少三个数组,其他则不指定)