众所周知,正常的变量里存放的都是数据,但是指针变量里存放的是地址,但是指针有好多种调用形式,先来一起感受一下:
就拿上面的案例来说哈:现在p是指针,指向数组arr的起始地址
直接输出 p ⇒ 打印的是p里面保存的那个地址,直接输出,因为指针保存的就是地址;
输出 *p ⇒ 打印的是p指向的值,比如这里指向arr起始地址,那输出的就是arr[0]的值
输出 &p ⇒ 打印的是p自身在内存中的地址,因为p本身在内存里也占用空间啊,本身是有地址的;
输出 ++p ⇒ 打印的是p指向当前元素的的下一位元素的值,不如这里就是输出arr[1]的值;
一、指针在基本数据类型里的引用:
说一下大致实现思路:p指向short类型数组date,q指向double类型数组bill,两个指针同时向后移动,内存地址的变化如上。
- 为什么 date 数组每次向后移动2个字节,bill 类型数组每次向后移动8个字节?
答:因为date是short类型的,每个元素占两个字节,bill是double类型的,每个元素占用8个字节。
启示:在C中,对一个指针+1的结果是对该指针增加一个存储单元,对数组而言,地址会增加到下一个元素的地址,而不是下一个字节。
dates + 2 == &dates[2]; //如果现在指针指向dates[0],给指针+2就是指针指向dates[2]
*(dates + 2) == dates[2];//相同的值
二、指针与二维数组
假设现在定义一个二维数组a[3][4];定义一个指针p指向这个二维数组a;
int a[3][4];
int *p = a; //p指针p指向数组a的首元素地址
如上图所示
想取 a [ i ] [ j ] 的内容:
- ( *(a + i) + j), 因为a是而且数组首元素的地址,先+i ,偏移 i 个单位,找到了第 i 行,然后解引用,取出第 i 行的地址,然后再+j , 偏移 j 个单位,现在指针已经指到了 a [ i ] [ j ] 的地址,再加上 * 解引用就得到了a [ i ] [ j ] 元素的内容。
想取 a [ i ] [ j ] 的地址:
*( a + i ) + j ,思路来同上,先取 a 的地址,然后+i 偏移 i 个单位从而找到第 i 行,解引用后+j 偏移 j 个单位从而找到第 j 列,现在找到了a [ i ] [ j ] 的地址,要得到地址就不用解引用了,
需要注意的几个点:
int a = 0; //a是 数值
int arr[10]; //a是数组
int *p = a; //a是变量
int *q = arr; //arr是一个地址,不是数值
int *r = arr[1]; //arr[1]是一个数值,不是地址
int *s = &arr; //s存储的是整个arr数组的地址,s+1 表示的不是arr[1],而是整个arr[10]以后的空间(比如这里arr[10]占用40个空间,那么s+1就是指针s往后移动40个字节)
三、二级指针
思路和一级指针类似,但是二级指针指向的是一级指针的地址