说到C语言,就不得不说到指针,指针是有点难理解,对于刚学C语言的同学来说是很痛苦的。。。以前对指针的概念很模糊,只知道指针和地址相关,但是最近看了一本《深入理解计算机系统》,感觉好像有点开窍了,再加上stm32的寄存器开发,以及最近在Linux中总是看到多重指针,于是花了点时间去理顺一下,在这做个总结吧。
从底层讲起
计算机的内存是无序(没有序号)的,为了方便人的操控,于是把物理的地址映射到逻辑地址,即变成有序号的地址了,也就是我们看到的程序中的那些地址,形象的比喻是 存储器是一个很大的字节数组,这个数组是由很多个内存块组成的,每个块呢都有其唯一的编号,可以理解为是下标,那个编号(下标)就是 地址啦 ,我们经常说有个值保存在某个地址上,其实就是这个值放在的这个地址指向的内存块中
我们举个例子
int a = 10;
把10 存进去变量a中是吧,这我们都知道,按照我上面收的,值是保存在地址指向的内存里,假如这个值是放在 地址 0x000080 所指向的内存中
画个图比较形象点,但是你看,我每次操作都要写个0x0000080然后怎样怎样 ,这是不是很繁琐呢, 所以我们引用了变量,更方便人们来操控这些值
到了这,我们明白数值是和地址的关系,我们现在再来讲指针
在一些入门的书籍都是这样写的
int a = 10;
int *p = &a;
int * p 我们根据优先级可以 这样来写 (int *) p
这个司空见惯了,我们来分析下,10 这个值存在了一个地址所指向的内存中,我们用变量a来代表这个地址,&符号是取地址符,int * 是一个 整型的指针 的 数据类型,也是一个数据类型,只不过他是这个类型是用来声明这个变量是用来 储存地址的
int *p = &a; 几时把a的地址赋值给p;我们看下代码
#include <stdio.h>
int main()
{
int a = 8;
int *p = &a; //a的地址赋给了 p
printf(" a = %d \n",a);
printf("&a = %p \n",&a); //取a的地址
printf(" p = %p \n",p); //p的值是什么呢
}
我们可以看出,这个整型指针类型的 p 的值是 和 &a的值是一样的,p也是个变量, 那么 这个 p有值 ,那肯定个有存放值的 内存啦,那么的话肯定有地址咯, 仿照按照上面说的 p的值存放在,p的地址所指向的内存中,我们在来看看代码
#include <stdio.h>
int main()
{
int a = 8;
int *p = &a; //a的地址赋给了 p
printf(" a = %d \n",a);
printf("&a = %p \n",&a); //取a的地址
printf(" p = %p \n",p); //p的值是什么呢
printf("p= %p (hex)\n",&p); //这个是变量p的地址 & 是取地址的意思(多说几遍)
}
果然,跟我们推测的一样,也是有个不一的值,在这里 a的地址和p的地址相差 4,我们都知道int 的类型是 4个字节的(32 位),
这个有什么相关联吗??
(*补充下吧,知道了就跳过 *:上文说了,内存是个大数组(比喻),数组是有下标的,一个下标(地址)对一个小块内存,我们称他为内存块, 书上这个内存是大多是 8 比特位的 ,就是一个字节喽,32位刚好四个字节,也就是一个整型数据的大小,也就 是四个地址的内存块的和,有因为 内存的取用是用顺序的(高地址到低地址),所以a和p的地址相差 4 ,你看,数据类型的和地址有着很多的关系的 。)
我们在书上还看过这个样的代码
printf(" *p = %d \n",*p);
我们运行下
看! *p的值是 和 a一样的,我推测下
p的作用是什么?
在这里*可不是乘 ,而是 取值,取什么值?
取地址所指向的值,在这里 *p 是指 以p的值为地址(前面说了p的值是变量a的地址) ,通过这个地址来找到内存中所存放的值(这一点很重要,要理解)(像立即数寻址一样)
所以有了 *p = a 这一说法 , *p也叫指针变量,这样一来,我们可以不对变量a操作,也可以间接修改 a 的值了! 这也是指针的厉害之处 !
普通的一级指针我们大致上了解 , 现在我说下 多重指针 (以二级指针为例 -)
二级指针 是这样的
int *p;
有两个 ,依照最开始说的 int **p 看成 (int *) *p(符号的优先级),看,现在还是一个 int *的类型,变量是 *p ,*p是啥?上面我们说了 p,仿照p的, *p的意思是 ,p是个指针变量,既然是变量是可以存放值得呀,这个变量又是指针变量, 是专门存放地址的变量, 就是以p的值为地址 ,通过这个地址来找到指向内存中所存放的值, 我们看代码(二级指针用q来表示)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200619092246287.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3JvdXNlMjYxNw==,size_16,color_FFFFFF,t_70
看,q变量的值,正是 &p,q是存放了变量p的地址
*q 是 p的值,跟我们说的一样, *是其通过以变量所保存的值为地址,来访问改地址的内存, *q 通过 q的值 0x0028FEB8,以这个值为地址 找到了以该地址的所指向的内存, 我们发现q的值正好的 p的地址.
我们再来看一段代码
#include <stdio.h>
int main()
{
int a = 8;
int *p = &a; //a的地址赋给了 p
int **q = &p;
printf(" a = %d \n",a);
printf("&a = %p \n",&a); //取a的地址
printf(" p = %p \n",p); //p的值是什么呢
printf("&p= %p (hex)\n",&p); //这个是变量p的地址 & 是取地址的意思(多说几遍)
printf("*p = %d \n \n",*p);
printf(" q = %p \n \n",q);
printf("* q = %p \n \n",*q);
printf("q的地址 = %p \n \n",&q);
printf("**q = %d \n",**q);
}
加了一行 这个
printf("**q = %d \n",**q);
**q怎么是 8呢?
上面我们知道 *q的值是 p的值 ,我们这来看
**q -> *(*q)
*q = p
**q -> *(*q) -> *(p)
p=0x0028FEBC
还是上面说的 *是通过以变量的值作为地址,再来访问内存,所以 才出现了 **p =a =8
我们是不是对二级指针有较好的理解啦
就先到这里啦
多重指针的使用可以点这里