引言

对于指针数组和数组指针的概念,相信很多人经常会感到迷惑,见到二者一时不能分辨究竟对应哪一个才是对的。接下来我们来分析一下二者区别。
我们来看一下这个示例代码:

int *ptr1[10];int (*ptr2)[10];

对于上述代码语句,你是否能分清哪一句代码声明的是指针数组,而哪一句代码声明的又是数组指针呢?
答案是第一行代码声明的ptr1是一个指针数组,数组名为 ptr1,而“int*”修饰的是数组的内容,该数组包含 5 个指向 int 类型数据的指针。第二行代码声明的ptr2则是一个数组指针,指针变量名为 ptr2,而 int 修饰的是数组的内容,即数组的每个元素。即ptr2 是一个指针,它指向一个包含 5 个 int 类型数据的数组。要想进一步弄清楚二者区别,我们接着看后边内容。

一、指针数组和数组指针的概念

  • 指针数组: 指针数组可以说成是”指针的数组”,首先这个变量是一个数组,其次,”指针”修饰这个数组,意思是说这个数组的所有元素都是指针类型,在32位系统中,指针占四个字节。

  • 数组指针: 数组指针可以说成是”数组的指针”,首先这个变量是一个指针,其次,”数组”修饰这个指针,意思是说这个指针存放着一个数组的首地址,或者说这个指针指向一个数组的首地址。

二、指针

为进一步理解指针数组和数组指针,我们回顾一下指针:

int var = 20;//var是变量,普通变量存放的是实际的值int *p;//*p是指针,指针变量存放的是地址p = &var;//p的值是var的地址,指针变量的值是具有实际值的变量的地址*p = 10;cout<< var <<endl;;

上述代码执行结果为10。
其中,指针变量有类型,即指针存放的地址指向的数据类型。“ * ”用来访问指针的值所表示的地址上的变量;“&”用来取得变量的地址;此时,我们可以得到*p=var,它们完全等价,具体原理可以写成:

*(访问指针的值所记录的地址)+p(p的地址)=var

考虑一下代码:

#include using namespace std;int main() {   int arr[5] = { 1, 2, 3, 4, 5 };   int *ptr = arr; //ptr指针指向数组第0个元素的地址  cout<< ptr <<endl;  return 0; }

再考虑如下声明:

int (*ptr)[5];

ptr指针指向一个大小为5的int型数组,由于[]的优先级高于*,因此加小括号即可让指针指向整个数组。ptr的类型是“指向数组中5个整数的指针”。

三、C/C++运算符优先级

为了更进一步方便看清代码意义,分解代码变量声明内容,我们来看一下C/C++中运算符的优先级。从上到下,从左到右,优先级一次减弱。

从上述表中我们可以看到,()、[]、* 的运算级优先级依次递减。
因此,对于指针数组来说,[] 的运算级高于 * 的运算级,则现有数组,再有指向数组元素的指针。而对于数组指针,() 运算级最高,先执行圆括号中的 * 获得指针,然后再让指针指向整个数组。

四、示例代码解析

在进行上述了解之后,我们再来看一下下边的示例代码:

int arr[3]={123};int (*p1)[3] = &arr;

注意第二行代码写法,下述写法是错误的:

int (*p2)[3] = arr;

在上面的示例代码中,&arr 是指整个数组的首地址,而 arr 是指数组首元素的首地址。虽然第二种写法是错误的,所表示的意义不同,但二者之间的值却是相同的。为什么语句“int(*p1)[3]=&arr”是正确的,而语句“int(*p2)[3]=arr”却在有些编译器下会报错呢?

究其原因,在 C/C++ 中,对于变量的类型有严格要求,其涉及的变量类型是强类型模式。赋值符号“=”号两边的数据类型必须是相同的,如果不同,则需要显示或隐式类型转换。在这里,p1 和 p2 都是数组指针,指向的是整个数组。p1 这个定义的“=”号两边的数据类型是一致的,而 p2 这个定义的“=”号两边的数据类型则不一致(左边的类型是指向整个数组的指针,而右边的数据类型是指向单个字符的指针),因此会提示错误信息。