数组指针定义:
数组指针就是指向数组的指针,定义好并初始化一个数组指针之后该指针中保存的就是指向的数组的地址(是整个数组的地址,而不是数组首元素的地址)
int a[5] = {1, 2, 3, 4, 5};
int (*p)[5] = &a;
上述代码段中,定义了一个数组指针p指向一个长度为5,元素类型为整型的数组a。
下面我们来分析一下这样一个问题:对数组指针作解引用操作后得到的是什么?比如对上述的数组指针a作解引用操作*a,会得到数组中元素的值吗?如果不是,那结果应该是怎样的?
我们可以先拿一种基本数据类型的指针来推敲一下,如果一个整型指针pa指向一个整型变量m,那么pa当中就保存着变量m的地址,而*pa操作就会得到m这个整型变量中的值。
类比一下,对整型指针作解引用得到的是整型变量的值,那么对数组指针作解引用得到的就应该是数组的值,但并不是数组中具体的元素的值,而是数组首元素的地址。(也可以这样理解:指针p中的值原本为整个数组a的地址,即p = &a, 而作了解引用操作后相当于是去掉了a前面的&运算符,即 *p = a, 而数组名a就是数组a首元素的地址。 当然在后续中*p和a就是等价的,*p[0]就等价于a[0],都表示数组首元素)。
既然对数组指针解引用只能得到数组的首元素地址,那么怎样才能拿到数组中元素的值呢?那就需要再次对地址做一次解引用的操作,下面以一个数组指针指向一维数组的例子给出说明:
int a[5] = {1, 2, 3, 4, 5};
int (*p)[5] = &a;
for(int i = 0; i < 5; i++){
cout << *(*p + i) << endl;
// p = &a
// *p就相当于是a(首元素地址)
// (*p + i)就是a中第i个元素的地址
//对每个元素地址作一次解引用操作就得到了每个元素值
}
这种方式来获取数组中的元素看起来非常的繁琐,实际上,很少会去用数组指针指向一维数组,使用数组指针的情形一般都是针对二维或以上的数组。 上面提到,解引用和下标引用的作用是相同的,即若要由一个数组指针得到某个具体的数据元素的话,可以有四种的选择,分别是:两次解引用, 一次解引用 + 一次下标引用, 一次下标引用 + 一次解引用, 两次下标引用,下面以一个数组指针指向二维数组的例子来说明这种用法:
void display(int (*p)[5], int x, int y){
for(int i = 0; i < x; i++){
for(int j = 0; j < y; j++){
//p中存放的是arr(二维数组)首元素的地址,是一个一维数组的地址
//则*p就相当于是arr[0]
cout << *(*(p + i) + j) << " ";
cout << (*(p+i))[j] << " ";
cout << *(p[i] + j) << " ";
cout << p[i][j] << " ";
}
cout << endl;
}
}
int main(){
int arr[3][5] = {{1, 2, 3, 4, 5}, {2, 3, 4, 5, 6}, {3, 4, 5, 6, 7}};
display(arr, 3, 5);
return 0;
}
上述display函数中的四种写法是等价的,数组指针p指向长度为5,元素为int型的数组,调用display函数时,把二维数组arr的首元素地址&arr[0]传了过去,就相当于是p指向arr中第一行的元素,那么*p就真正得到了第一行的数据,也可以理解为得到了第一行第一个元素的地址。此时还只是拿到了具体元素的地址,并没有得到元素值,要想获取数组元素的值,需要在上述的基础上再进行解引用或是下标引用的操作。上述代码段中的四种写法是等价的,即解引用和下标引用可以任意组合使用,效果相同。
对于数组指针的见解就先谈到这里了,重要的就是记住这一点:对数组指针作解引用的操作并不能得到数组元素的值,而只能获取指针指向的数组首元素的地址,要想访问到数组元素,还需要进一步执行解引用或下标引用的操作。