与指针数组相比,数组指针更难理解一点,这里简单做一下对比,并重点说明什么是数组指针。
指针数组
- 从命名规则来看:
数组就是集合,指针数组就是一堆指针,就是一堆指针集合在一起。 - 从定义规则来看:
int *p[4];
。根据结合顺序,先执行p[4]
,是一个数组,然后int *
说明元素类型是整型指针。
前面提到过(指向指针的指针那篇),指针数组可以用来对一个数据集合进行再分类。
数组指针
那么什么是数组指针呢?
- 从命名规则来看:
整型指针意思是指向整型变量的指针,那么类比过来,数组指针就是指向数组变量的指针。 - 从定义规则来看:
int (*p)[4]
。根据结合顺序,先执行(*p)
,是一个指针,然后[4]
,说明指向一个有四个整型变量的一维数组数组。
实际上,写成如下形式更容易理解:
int [4] *p;
// 定义指针,指向的数据类型是int [4]
对比
int *p;
// 定义指针, 指向的数据类型是int
指针的步长
定义一个指针实际上需要给出两方面的信息,一个是指针指向的地址,对于数组而言,一般是数组的地址;二是指针的步长,也就规定了指针加1时,指向的地址移动多少位。
指针与一维数组
1. 指向一维数组首元素的指针
#include <stdio.h>
int main()
{
int a[] = {1, 2, 3, 4, 5};
int *p = a;
printf("p: %p, *p: %d\n", p, *p);
printf("p+1: %p, *(p+1): %d\n", p+1, *(p+1));
return 0;
}
// 输出结果:
p: 0060FEF8, *p:1
p+1: 0060FEFC, *p+1:2
定义了一个指针,指向数组名,也就是指向数组的首元素地址,指针+1后,指针指向的位置往后移动4位,指向一维数组的第二个元素。
2. 指向一维数组的指针
首先说明一个结论,指向一维数组一般是不用数组指针的,如果强行使用呢?
对上述代码进行简单地修改,以下代码正确么?
#include <stdio.h>
int main()
{
int a[] = {1, 2, 3, 4, 5};
int (*p)[5] = a;
printf("p: %p, *p: %d\n", p, *p);
printf("p+1: %p, *(p+1): %d\n", p+1, *(p+1));
return 0;
}
上面的代码中,定义一个数组指针指向一维数组a。
编译警告:warning: initialization from incompatible pointer type
我们从指针的两个要素分析一下a
和p
:
a是数组名,根据前面的知识,我们知道,数组名也是首元素的地址,因此“指针a”的地址是首元素的地址;那么步长呢?在数组定义中已经指明这是一个存储整型变量的一维数组,因此步长是4个字节。综上,a其实就是一个指向整型元素的指针。与int b = 10; int *a = b;
中的a没有区别。
把p的定义改写一下形式,int [5] (*p)
。p是一个数组指针,步长为一个包含5个整型变量的一维数组,也就是20个字节。显然嘛,两边指针不匹配。
那么,如何修改才能使得正常编译并达到我们想要的效果呢?(在此注意,对于一维数组这样写纯粹是找麻烦,这里只是说明原理)。
如何访问数组的第二个元素“2”呢?改写成一下形式:
#include <stdio.h>
int main()
{
int a[] = {1, 2, 3, 4, 5};
int (*p)[5] = &a;
printf("a[1] = %d", *(*(p+0)+1));
return 0;
}
数组首元素的地址的值和数组地址的值是相等的,但是步长不同。
&a 是整个数组的地址(地址为首元素,步长为5),所以 &a + 1 指向整个数组最后的位置
指针与二维数组
二维数组才是数组指针的用武之地。通过数组指针索引二维数组元素。
#include <stdio.h>
int main()
{
int a[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
int (*p)[4] = a;
// int (*p)[3][4] = &a;
printf("a[1][3] = %d", *(*(p+1)+3));
//printf("a[1][3] = %d", *(*(*(p+1)+3)));
return 0;
}
当然也可以采用注释的写法(这个还不太明白。。。)
网友评论