1、一维数组
一维数组举例,如清单1:
- #include <stdio.h>
- int main(void)
- {
- int a[5] = {1, 2, 3, 4, 5};
- int *p = a; //等价于int *p = &a[0];
- //绝不等价于int *p = &a;
- int (*pa)[5] = &a;
- printf("a = %p, p+1 = %p, pa+1 = %p\n", a, p+1, pa+1);
- return 0;
- }
第5行定义了一个一维的整型数组a,共有5个元素,并被初始化为整数1、2、3、4和5。注意,这里所说的“整型数组”的“整型”其实指的是数组中单个元素的数据类型,数组本身的数据类型是一种组合型的数据类型,并没有相应的关键字来表示。
回顾一下指针变量的定义,如第7行定义了一个指针变量p,定义中的关键字int指的是指针变量p将只能匹配整型数据的首地址。而数组名a代表的是其第一个元素a[0]的首地址(数组名代表着数组的首地址的说法欠准确),也就是说把a(等价于&a[0])赋给指针变量p(这时候就可以说p指向了a[0]),它们的数据类型是相匹配的,因为a[0]是整型变量,而p只匹配整型数据的首地址。
虽然&a与&a[0]的值相同,但它们的数据类型并不相同,a[0]的数据类型为int,而整个数组的数据类型为int [5](是一种组合数据类型,由int和[5]共同决定),所以与&a匹配的指针变量只能是类似于第10行的pa。
也就是说,数组单个元素的数据类型和指针变量将要指向的数据类型是一致的。
例子输出结果:
- a = 0xbfd2d1b4, p+1 = 0xbfd2d1b8, pa+1 = 0xbfd2d1c8
p+1为第二个元素a[1]的首地址,而pa+1的值是整个数组后面的那个地址。
2、多维数组
在C语言当中,没有所谓的多维数组,只有数组的数组。
多维数组举例,如清单2:
- #include <stdio.h>
- int main(void)
- {
- int a[2][3][5] = { { {1, 2, 3, 4, 5 },
- {6, 7, 8, 9, 10},
- {11, 12, 13, 14, 15}
- },
- { {16, 17, 18, 19, 20},
- {21, 22, 23, 24, 25},
- {26, 27, 28, 29, 30}
- }
- };
- int (*p0)[2][3][5] = &a;
- printf("&a = %p, p0 = %p, p0+1 = %p\n", &a, p0, p0+1);
- int (*p1)[3][5] = a; //等价于int (*p1)[3][5] = &a[0];
- printf("p1 = %p, p1+1 = %p, ***(p1+1) = %d\n", p1, p1+1, ***(p1+1));
- int (*p2)[5] = a[0]; //等价于int (*p2)[5] = &a[0][0];
- printf("p2 = %p, p2+4 = %p, **(p2+4) = %d\n", p2, p2+4, **(p2+4));
- int *p3 = a[1][2]; //等价于int *p3 = &a[1][2][0];
- printf("p3 = %p, p3+2 = %p, *(p3+2) = %d\n", p3, p3+2, *(p3+2));
- printf("a[1][0][0] = %d, a[1][1][0] = %d, a[1][2][2] = %d\n",
- a[1][0][0], a[1][1][0], a[1][2][2]);
- return 0;
- }
第5行,a是一个三维数组,共有两个元素,每个元素的数据类型为int [3][5]。
a[0]和a[1]分别都是二维数组,每个数组共有三个元素,每个元素的数据类型为int [5]。
a[0][0]、a[0][1]、a[0][2]、a[1][0]、a[1][1]和a[1][2]分别都是一维数组,每个数组共有五个元素,每个元素的数据类型为int。
例子输出结果:
- &a = 0xbfdb1e88, p0 = 0xbfdb1e88, p0+1 = 0xbfdb1f00
- p1 = 0xbfdb1e88, p1+1 = 0xbfdb1ec4, ***(p1+1) = 16
- p2 = 0xbfdb1e88, p2+4 = 0xbfdb1ed8, **(p2+4) = 21
- p3 = 0xbfdb1eec, p3+2 = 0xbfdb1ef4, *(p3+2) = 28
- a[1][0][0] = 16, a[1][1][0] = 21, a[1][2][2] = 28
结合下面的图形好好地体会为什么输出这样的结果:
3、指针数组和数组指针
指针数组,是一个数组,只不过所有元素都是指针变量。
数组指针,是一个指针变量,只不过它将指向的数据类型为某种形式的数组,如清单1中的pa,清单2中的p0、p1和p2。
指针数组的例子,如清单3:
- #include <stdio.h>
- int main(void)
- {
- int a[3] = {1, 2, 3};
- int b[3] = {4, 5, 6};
- int *p[2] = {a, b};
- printf("p[0][1] = %d, *(p[1]+2) = %d\n", p[0][1], *(p[1]+2));
- return 0;
- }
例子输出结果:
- p[0][1] = 2, *(p[1]+2) = 6
第8行定义了一个指针数组,共有两个元素,每个元素都是将要指向整型数据的指针变量。
p[0]的值就是数组a的首地址,所以p[0][1]就等价于a[1]。
p[1]的值就是数组b的首地址,然后加2获得数组b第3个元素的首地址,最后通过间接运算符(*)取出第3个元素的值。
4、数组在函数形参中的应用
数组在函数形参中等价于一个相应的指针变量。如清单4:
- #include <stdio.h>
- void func(int a[2][3]) //这里的int a[2][3]等价于int (*a)[3]
- {
- int i, j;
- for (i = 0; i < 2; i++)
- for (j = 0; j < 3; j++)
- printf("a[%d][%d] = %d\n", i, j, a[i][j]);
- }
- int main(void)
- {
- int b[2][3] = { {1, 2, 3}, {4, 5, 6} };
- int (*p)[3] = b;
- func(p);
- return 0;
- }
例子输出结果:
- a[0][0] = 1
- a[0][1] = 2
- a[0][2] = 3
- a[1][0] = 4
- a[1][1] = 5
- a[1][2] = 6
整个例子的含义是p =&b[0],而数组指针a = p。