一.指针变量的基础知识
1.1指针变量的概念 —— 取地址操作符( & )
在探讨什么是指针之前我们先想一个现实中的情况,假如你的同学邀请你去他的寝室,你一定需要提前问他的寝室号是多少
而指针变量相当于内存中的寝室号,它保存的是每个变量/函数/数组等的地址
注:我们常说的指针其实是指针变量,指针实际上是一个地址(即寝室号)
取地址操作符( & ) 可以理解为找你同学要他的寝室号这个行为
在内存中,& 后面加 变量/函数/数组 代表 变量/函数/数组 的地址
例如:
![](https://img-blog.csdnimg.cn/direct/2e2072c9dd4248d5964bd288aedcacda.png)
图中 000000000062FE1C 就是 变量 a 的地址(房间号)
1.2指针变量的定义
在图1.1中,我们打印了 a 的地址,是通过 &a 这样取地址的行为(即你向你同学问他的寝室号)做到的,但是你不可能每次去你同学的寝室之前都问他的寝室号是多少,这样效率不高且没有礼貌(hhhh),在内存中同样如此,我们需要用一个变量来保存指针,即指针变量。
注:我们常说的指针其实是指针变量,指针实际上是一个地址(即寝室号)
在C语言中,我们使用 * 来表示指针变量
和定义其他类型变量有所不同的地方是, * 前面会再加一个类型,代表指针变量实际指向的地址所保存的内容是什么类型的
例如:
int a = 211;
int * p = &a;
在上图中 * 表示一个指针变量, 变量名为 p ,&a 表示取出 a 的地址,int 表示 a 实际保存的是一个int类型(即 * 表示寝室号, p 表示你把寝室号记在了一个叫 p 的日记本上,&a 表示你问同学他的寝室号是多少, * 前面的 int 表示 a 这个寝室号里面实际住的是你同学(是人这个类型),在这里我们是int类型)
你询问你的同学他的寝室号是多少这个行为是 &a, 你把他的寝室号记在一个名为 p 的日记本上, 当你下一次去找他寝室找他的时候 就可以直接看日记本(即直接访问 p 即可),而不需要再问他一次
1.3解地址操作符( * )
回到刚刚的例子,你的同学告诉了你他的寝室号为211,那么你很快就可以找到他寝室的位置,即是2楼第11个房间。
解地址操作符(*)相当于你找房间的这个过程
在内存中, * 后面加 变量/函数/数组 可以直接找到 该变量/函数/数组
例如:
二.字符指针
2.1字符指针的定义
在1.2中我们介绍了 int 类型的指针(即整数类型指针),现在我们来了解一下字符指针
我们都知道定义一个字符在C语言中是通过如下方式
char c = 'w';
char 代表字符类型
字符类型指针就是字符指针,即 指针变量保存的地址中的内容类型是char
定义如下:
char c = 'w';
char * pc = &c;
2.2指针与字符串
但假如每次只保存一个字符的地址,我想要输入一串字符串(例如:"Hello")难道要每个字符都保存在一个指针变量里面么?那样会显得太麻烦,因此我们规定字符类型指针也可以保存字符串的地址
定义如下:
char * pc = "Hello";
但这样又出现了一个新的问题,我们知道,当 保存一个字符 'w' 的地址的时候, pc 保存的就是 'w' 的地址,那当保存一个字符串 "Hello" 的地址的时候,是保存 首字母 H 的地址,还是把 Hello这五个字母的所有地址都保存在 pc 里面,还是随机保存 Hello 这五个字母中随机一个字母的地址?
我们可以测试一下,以下为测试答案:
由测试内容可知,pc 保存的不是整个字符串的地址,而是第一个字母的地址,所以当我们解地址时打印出来的是第一个字母 H。
那么怎么打印所有字母呢?
我们知道,一个字符所占内存为一个字节,我们假设第一个字符的地址为0xff1204(这里只是为了方便举例,实际地址要看编译器如何进行分配),字符串的所有地址如下:
而指针变量 pc+i (此时 i 等于0) 最先保存的地址为 0xff1204 指向 H
经过一次循环后 i 等于 1 ,pc+1保存的地址则为第二个字母的地址,*(pc+1)则找到第二个字母e,并打印出来
.....
.....
以此循环直到打印出所有字母
三.数组指针
3.1数组指针的定义
同字符指针一样,数组指针指的是 指针保存的地址所指向内容是数组
我们定义一个数组变量是通过如下方式:
int arr[10] = {0};
其中 [ ] 表示定义的是一个数组变量,变量名为 arr ,int 表示 数组中保存的所有元素是 int 类型
数组指针可以进行类比得到如下定义方式:
int (* pArr) [10];
注意: [ ] 的优先级高于 * ,如果不将 * 和 pArr 通过括号括起来,编译器将自动把 pArr 与后面的 [ ] 结合,那么int * pArr[ ] 就是一个数组,数组中每个元素是int * 类型,而不是指针了
3.2数组指针的实例
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int (* pArr)[10] = &arr;
如上述示例: * 与 pArr 先结合构成一个指针,[ ] 此时变成一个数组,int (* pArr)[10] 指 一个名为 pArr 的指针保存 一个数组的地址,该数组的元素有10个,元素的类型为 int
3.3如何使用数组指针
在介绍怎么使用数组指针之前,我们先看一个示例:
看上述代码的输出结果,我想要输出 数组 arr 的每一个元素,但输出的结果却完全不一样,这是为什么?
原因是在 *(pArr + i) 这里出现了问题
注意:arr 是数组名,同时也表示数组首元素的地址,但是存在两个例外
①sizeof 后面加数组名,此时数组名代表整个数组的地址
②& 后面加数组名,此时数组名代表整个数组的地址
在上述代码中,我们让
int (*pArr) [10] = &arr
此时的 arr 代表的就是整个数组的地址
![](https://img-blog.csdnimg.cn/direct/3f31f288b915420a96531e2abe32d605.png)
正确写法如下图所示:
我们来解析一下 *(*(pArr)+i) 到底是怎么遍历数组中的每一个元素的
*(pArr) 保存的是数组的第一个元素的地址
*(pArr) + i 保存的是数组中第i个元素的地址
*(*(pArr)+i) 是通过该数组第 i 个元素的地址找到第 i 个元素
综上所述:可以理解为数组指针拥有两层外壳,当对 pArr 进行解地址操作时,只是去掉了第一层外壳,找到了整个数组的地址,如果要对 arr 数组中的单个元素进行操作的话,则需要进行第二次解地址操作,找到单个元素的地址
以上仅是我个人对C语言指针的浅薄理解,如有错误,还请指正!