以下是它的实际工作原理,可查看代码和注释:
#include <stdio.h>
int x[3][5] =
{
{ 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 10 },
{ 11, 12, 13, 14, 15 }
};
int (*pArr35)[3][5] = &x;
int (*pArr5a)[5] = x;
int (*pArr5b)[5] = &x[0];
int *pInta = x[0];
int *pIntb = *x;
int *pIntc = &x[0][0];
int main(void)
{
printf("&x=%p x=%p &x[0]=%p x[0]=%p *x=%p &x[0][0]=%p\n",
pArr35, pArr5a, pArr5b, pInta, pIntb, pIntc);
return 0;
}
样例输出:
&x=0040805c x=0040805c &x[0]=0040805c x[0]=0040805c *x=0040805c &x[0][0]=0040805c
所有的指针结果在数值上是相同的,因为我明确或隐式地使用了索引0,并且数组是连续的,它们的第一个(也就是0号)元素总是在数组中最低的地址处。所以,即使有3种不同的指针类型,它们都有效地指向x[0][0],即等于1的元素。
这种将数组衰减为指针的特性是C和C++非常重要的特性,尽管它不容易立即理解。
当我们传递指向数组的指针时,它让我们编写更紧凑的代码,我们可以只写数组的名称而不是取其第一个元素的地址:
char str1[] = { 's', 't', 'r', '1', '\0' };
char str2[] = "str2";
printf("%s %s %s %s\n", &str1[0], str1, &str2[0], str2);
输出:
str1 str1 str2 str2
它还让我们可以做疯狂的事情:
int y[3] = { 10, 20, 30 };
printf("%d %d %d %d\n", y[2], *(y+2), *(2+y), 2[y]);
输出:
30 30 30 30
这是因为在数组和指针中,a[b]
等同于 *(a+b)
。