目录
一、什么是指针
- 地址就是指针
- 数据和代码:
数据和代码都以二进制的形式存储在内存中
操作系统会给不同的内存块指定不同的权限
拥有读取和执行权限的内存块就是代码
而拥有读取和写入权限(也可能只有读取权限)的内存块就是数据
- CPU只能通过地址来取得内存中的代码和数据,CPU 访问内存时需要的是地址,而不是变量名和函数名!变量名和函数名只是地址的一种助记符,当源文件被编译和链接成可执行程序后,它们都会被替换成地址。编译和链接过程的一项重要任务就是找到这些名称所对应的地址。
- 注意:虽然变量名、函数名、字符串名和数组名在本质上是一样的,它们都是地址的助记符,但在编写代码的过程中,我们认为(1)变量名表示的是数据本身(2)函数名、字符串名和数组名表示的是代码块或数据块的首地址。
二、指针变量(*取数据,&表地址)
- 数据在内存中的地址也称为指针,如果一个变量存储了一份数据的指针,我们就称它为指针变量。
- 同时使用&和*
假设有一个 int 类型的变量 a,pa 是指向它的指针,那么*&a和&*pa分别是什么意思呢?
*&a可以理解为*(&a),&a表示取变量 a 的地址(等价于 pa),*(&a)表示取这个地址上的数据(等价于 *pa),所以*&a仍然等价于 a。
&*pa可以理解为&(*pa),*pa表示取得 pa 指向的数据(等价于 a),&(*pa)表示数据的地址(等价于 &a),所以&*pa等价于 pa。
- 指针变量的计算
(1)数组中的所有元素在内存中是连续排列的,如果一个指针指向了数组中的某个元素,那么加 1 就表示指向下一个元素,减 1 就表示指向上一个元素,这样指针的加减运算就具有了现实的意义。
(2)除去数组等特殊数据体外,不要对指向普通变量的指针进行加减运算。(如果连续定义多个变量,它们有可能是挨着的,也有可能是分散的)
三、指针与数组
(一)数组指针
- 定义:如果一个指针指向了数组,我们就称它为数组指针(Array Pointer)。
数组指针指向的是数组中的一个具体元素,而不是整个数组,所以数组指针的类型和数组元素的类型有关,p 指向的数组元素是 int 类型,所以 p 的类型必须也是int *。
int arr[] = { 99, 15, 100, 888, 252 };
int *p = arr;
arr 是数组第 0 个元素的地址,所以int *p = arr;也可以写作int *p = &arr[0];。也就是说,arr、p、&arr[0] 这三种写法都是等价的。
- 访问数组元素的两种方案
引入数组指针后,我们就有两种方案来访问数组元素了,一种是使用下标,另外一种是使用指针。
(1) 使用下标
也就是采用 arr[i] 的形式访问数组元素。如果 p 是指向数组 arr 的指针,那么也可以使用 p[i] 来访问数组元素,它等价于 arr[i]。
(2) 使用指针
也就是使用 *(p+i) 的形式访问数组元素。另外数组名本身也是指针,也可以使用 *(arr+i) 来访问数组元素,它等价于 *(p+i)。
不管是数组名还是数组指针,都可以使用上面的两种方式来访问数组元素。不同的是,数组名是常量,它的值不能改变,而数组指针是变量,它的值可以任意改变。也就是说,数组名只能指向数组的开头,而数组指针可以指向数组开头,也可以指向其他元素。
- 假设 p 是指向数组 arr 中第 n 个元素的指针,那么 *p++、*++p、(*p)++ 分别是什么意思呢?
1、*p++ 等价于 *(p++),表示先取得第 n 个元素的值,再将 p 指向下一个元素,上面已经进行