指针数组
顾名思义,指针数组首先它是个数组,只是数组里存放的元素不是某个类型的数据,而是指向某个类型数据的指针,即存放指针的数组。
int* arr[3] = {*p1, *p2, *p3};
从符号优先级来看,中括号[]的优先级是要高于 * 的,所以,arr会先和[]共同构成一个数组,而int*则是用来说明数组中存放的元素的类型,即数组arr中存放的是3个指向int类型数据的指针。
数组指针
顾名思义,数组指针首先它是个指针,而该指针指向的是一个数组,准确的说,指向的是一个数组的首地址,即指向数组的指针。
int (*p)[3];
从符号优先级来看,* 首先修饰p构成一个指针,指针变量名为 p,前面的int则用来修饰数组内的元素,即指针p指向一个包含3个 int 类型数据的数组,而此处的数组是一个匿名数组。或者以下形式定义:
int arr[3] = {1, 2, 3};
int (*p)[3] = &arr;
注意:
我们知道,数组名本身就代表着数组中首元素的地址, 那么下面两种方式是不是都是对的呢?
int arr[3] = {1, 2, 3};
int (*p)[3] = &arr; //方式一
int (*p)[3] = arr; //方式二
答案是只有方式一是对的,&arr 是指整个数组的首地址,而arr则是指该数组首元素的地址,虽然值都是相同的,但所表示的意义确实又区别的。方式一”=”号两边的数据类型是完全一致,但是方式二”=”号两边的数据类型却是不同的,左边是指向数组的指针,但是右边是指向单个元素的指针,因此会产生如下的错误提示:
指针常量
顾名思义,指针常量首先它是个常量,而该常量是一个指针,换句话说,指针本身所指向常量/变量的地址值是不能改变的,但是可以通过指针取值去改变变量的值。
int a = 5;
int b = 8;
int* const p = &a; //指针常量在定义的时候就要给出初始值,并且就不能改变该指针的指向了
a = 6; //可以通过变量自身修改数值
*p = 7; //可以通过指针取值*p修改变量的数值
//p = &b; //不可以修改指针的指向,即指针存放的变量的地址是不允许修改的
注意:
const在 * 号的右侧,const代表常量,* 代表指针,指针常量,指针 * 在前,常量const在后;
一定要在指针常量定义的时候进行初始化,明确指针的指向;
指针常量不能一旦指向一个地址就不能再修改指向了。
常量指针
类别于数组指针,常量指针就是一个指向一个常量的指针,于指针常量不同的是,这个指针是可以改变的,也就是说指针可以修改指向别的常量/变量,但是不能够通过取值指针的形式来修改指针指向的值。
int a = 5;
int b = 8;
const int* p;
p = &a;
a = 6; //可以通过变量本身去修改数值
p = &b; //指针可以修改去指向别的常量/变量
*p = 7; //不可以通过*p的形式去修改数值,即不允许给常量指针赋值操作
注意:
const在 * 号的左侧,const代表常量,* 代表指针,常量指针,常量const在前,指针 * 在后;
不能给常量指针进行赋值操作,指针看起来好像指向了一个常量。
常量指针常量
常量指针常量可以理解为常量指针和指针常量二者的结合,所以常量指针常量既不可以修改指针指向的内容,也不可以修改指针的指向。
int a =5;
int b =8;
const int* const p = &a;
a = 6; //可以通过变量本身修改数值
//*p = 7; //不可以通过指针修改变量的数值
//p = &b; //不可以修改指针的指向
最后,引用一下别人的一个比喻来帮助大家记忆:
指针常量指向的地址是不能改变的,从始至终只指向同一个内存区域(自始至终指向心爱的人),所以他能够通过指针本身修改变量的数值(因为专一,所以他可以通过自身去影响他人);
常量指针就不一样了,它可以指向别的变量和常量,就像一个移情别恋的渣男,所以导致它不能够通过自己去改变变量(因为渣,所以不能以身作则去影响别人,从而改变别人);
而常量指针常量就是专一的不行了,简直是神的存在。
但是,三者都不能阻止常量自身去修改数值,因为即使我们本身再优秀,也不能阻止别人变心。