目录
1.内存和地址
a 内存的理解
b 如何理解编址
2.指针变量和地址
a 取地址操作符
b 指针变量
c 解引用操作符
d 指针变量的大小
1.内存和地址
a 内存的理解
假想这样一个场景,你的朋友找你玩,到了你家小区,如何让她迅速的找到你家呢?当然有很多方法,最直接有效的方法是你告诉她你家在几栋几号,这样就可以通过编号来迅速找到你。此时几栋几号就是你的地址。
当然,计算机CPU在处理数据的时候,需要的数据是在内存中读取的,处理后的数 据也会放回内存中,那么如何高效简洁的管理空间呢?其实也是把内存划分为⼀个个的内存单元,每个内存单元的大小取1个字节。
当然,需要我们了解一下计算机的进制转换,
1字节(byte)= 8比特(bit);比特是计算机中的最小内存单位
1KB =1024字节; 1MB=1024KB
1GB = 1024 MB; 1TB=1024GB
b 如何理解编址
CPU访问内存中的某个字节空间,必须知道这个字节空间在内存的什么位置,而因为内存中字节很多,所以需要给内存进行编址(就如同宿舍很 多,需要给宿舍编号⼀样)。 计算机中的编址,并不是把每个字节的地址记录下来,而是通过硬件设计完成的。 正如钢琴、吉他上面没有写上“都瑞咪发嗦啦”这样的信息,但演奏者照样能够准确找到每⼀个琴弦的每⼀个位置,这是因为制造商已经在乐器硬件层面上设计好了,并且所有的演奏者都知道。本质是⼀种约定出来的共识!
首先要明白计算机有很多硬件,这些硬件不完全相同,但是要分工协作共同完成工作,那么怎么能实现这个功能呢?那就更简单了,就是用线将它们连接起来。而我们真正需要注意的一个线叫做地址总线,可以这么理解,32位的计算器有32条这样的线,每个线有两种状态,分别是0和1,那么32根线一共能表示2^32种状态,这样的每个状态就是我们的一个地址,他们分别储存在不同的硬件上,地址信息被下达给内存,在内存上,就可以找到该地址对应的数据,将数据在通过数据总线传入CPU内寄存器。
简单的说,内存单元的编号==地址
一句话简明的说,地址就是指针,内存单元的编号 == 地址 == 指针
2.指针变量和地址
a 取地址操作符
在c语言中,我们创建一个变量的实质就是向内存申请一块空间 ,举个例子,我们创建一个变量a
int a = 10;//这个实质是向内存申请4个空间来存放a的数值
就是这个东西,每一个字节有一个编号
那我们如何获取a的地址呢?,这里就要用到取地址符号了&
取地址符号是单目操作符号,我们之前
结合我们常使用的打印数字来说明
#include <stdio.h>
int main()
{
int a = 10;
printf("%d", &a);
return 0;
}
这里这个取地址符号就取出a中较小地址,进行打印处理
我们这里用%p打印处理看看
虽然我们这里是较小的地址,但是是不是可以顺藤摸瓜我们直接获取其他地址啊,其实不同类型的指针的权限是不同的,这里我们后边说
好了,上边的这个&a其实就是一个指针变量,那么我们P=&a的话,这个P就是指针变量
b 指针变量
那我们通过取地址操作符(&)拿到的地址是⼀个数值,比如:0x006FFD70,这个数值有时候也是需要存储起来,方便后期再使用的,那我们把这样的地址值存放在哪里呢?答案是:指针变量中。
那么指针变量我们怎么表示呢?在c语言里用以下表示
int* pa = &a;
如何拆解指针类型?
OK,下面我们来看看这个该怎么写
char ch = ‘m’;
pc = &ch;//pc的类型怎么写
好滴,聪明的我已经知道了要用char*了,哈哈哈哈
c 解引用操作符
我们将地址保存起来,未来是要使用的,那怎么使用呢? 在现实生活中,我们可以通过仓库编号直接去拿放东西,C语言中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)指向的对象,这里必须学习⼀个操作符叫解引用操作符(*)。
#include <stdio.h>
int main()
{
int a = 10;
int* pa = &a;
*pa = 0;//解引用符号应用
return 0;
}
上述代码中的*pa就是解引用操作符,它的作用是通过pa的地址来找到对应地址的值,所以说*pa其实就是a,我们可以通过打印a,和*pa来进行验证
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int a = 10;
int* pa = &a;
*pa = 0;
printf("a=%d\n", a);
printf("*pa=%d\n", *pa);
return 0;
}
从而我们得到
其实取地址操作符&和解引用操作符*在一定程度上是互逆的,我们可以这样写
int a = 10;
*&a = 0;
然后我们可以看到结果
到了这里,有些同学会疑惑,既然我们通过了一个指针变量使a变为0,那为何不直接把a赋值为0,而要绕一圈子里?
其实这里就是将a交给pa来处理的,多一种处理方式。举个例子,就是有些大官看不惯一个人,他不好自己出手,就交给自己的小弟出手来解决,这种感觉,随着指针的学习,会越来越理解。
d 指针变量的大小
说来说去,指针就是内存变量,既然是变量,就会有他的大小,要想知道指针变量的大小,我们还要从内存说起。我们已经知道,32内存位计算器有32条地址总线,每条线有1和0两个状态,那么一个内存的编号就有32条地址线表示,一条地址线占一个比特位,那么32条地址线就是32个比特位,因此就是4个字节。同理,64位计算机的话,就是8个字节。我们可以通过sizeof函数来进行验证,验证代码如下
#define _crt_secure_no_warnings
#include <stdio.h>
int main()
{
printf("%zd\n", sizeof(char*));
printf("%zd\n", sizeof(short*));
printf("%zd\n", sizeof(int*));
printf("%zd\n", sizeof(float*));
printf("%zd\n", sizeof(long*));
return 0;
}
我们首先在x86环境里验证
可以发现无论哪个类型的指针变量的大小都是4。
然后我们在x64环境里进行验证
发现每个指针变量的大小都是8个字节。
上边的验证也很好的说明了指针就是内存,32位系统一个内存是4个字节,因而其指针变量大小也是4个字节。64位系统一个内存是8个字节,因而指针变量大小也是8个字节。