区别如下:
int (*arr1)[10]; // arr1 is a pointer to a 10-element array of int
int *arr2[10]; // arr2 is a 10-element array of pointer to int
这很重要 - 尽管最后有 [10],arr1 不是数组;它只存储一个单个指针值,这是int的一些10元素数组的地址。
在两种主要情况下会出现指向数组的指针 - 当 N 维数组表达式“衰减”为指针表达式时,以及当我们为 N 维数组分配内存时。
首先,衰减规则 - 除非它是 sizeof 或一元 & 运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,表达式 “T 的 N 元素数组”类型的 em> 将被转换或“衰减”为“指向T 的指针”类型的表达式,表达式的值将是第一个元素的地址数组。你可能以前见过这样的代码:
int arr[10];
int *p = arr; // arr "decays" to a pointer to its first element
表达式arr“衰减”从类型“int”的 10 元素数组到类型“指向int”的指针。
2D 数组也会发生同样的事情:
int arr[5][10];
int (*p)[10] = arr;
表达式arr“衰减”从类型“int 的 10 元素数组的 5 元素数组”到类型“指向 int 的 10 元素数组的指针”。
您还可以使用一元 & 运算符直接获取指向一维数组的指针:
int arr[10];
int (*p)[10] = &arr; // note presence of & operator here
但这并不常见。
数组指针的另一个用途是当我们想要动态分配一个连续二维(或更高维)数组时:
int (*p)[10] = malloc( sizeof *p * 5 ); // allocates space for a 5x10 array of int
表达式*p的类型是“int的10元素数组”,或者int [10],所以sizeof *p等价于sizeof (int [10]),所以@987654345 @call 为 int 的 5 个 10 元素数组留出了足够的空间。您可以像任何其他二维数组一样对该数组进行索引:p[i][j] = some_value();。该数组的行在内存中是连续的并且长度都相同,并且只需要一次调用free 即可解除分配。
您可能已经看到通过多个步骤动态分配二维数组的代码 - 首先您分配一个指针数组,然后为每个指针分配一个目标类型的数组,如下所示:
int **p = malloc( sizeof *p * R ); // allocates an R-element array of pointer to int
if ( p )
{
for ( size_t i = 0; i < R; i++ )
{
p[i] = malloc( sizeof *p[i] * C ); // allocates a C-element array of int
}
}
这里的区别在于,在第二种情况下,行在内存中不相邻 - 它不是一个单独的连续块。此外,不同的行可能有不同的长度(有时称为“锯齿状”数组)。在释放 p 之前,您还必须分别 free 每一行。
指针声明的基本规则是:
T *p; // p is a pointer to T
T *a[N]; // a is an array of pointer to T
T *f(); // f is a function returning pointer to T
T (*a)[N]; // a is a pointer to an N-element array of T
T (*f)(); // f is a pointer to a function returning T
T const *p; // p is a non-const pointer to const T - you can modify p to point
// to a different object, but you cannot modify the thing p points to
const T *p; // same as above
T * const p; // p is a const pointer to non-const T - you can modify what p
// p points to, but you can't modify p to point to a different object
// (which means p needs to be initialized to a valid pointer value
// when it's declared).
T const * const p; // p is a const pointer to const T - you can't update either
// p or *p
const T * const p; // same as above.