《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介
1、地址概念引入
在讲内存与地址
之前,我们讲个生活中的案例:
假设有⼀栋住宅,住宅有 100 个房间甚至更多,但是房间没有编号
,你的外卖小哥来给你送外卖,如果想找到你,就得挨个房子去找,这样效率很低,等找到你的时候,黄瓜饭都凉了!
怎么办呢?很明显我们如果根据楼层和楼层的房间的情况,给每个房间编上号,填上地址,如:
⼀楼:101,102,103...
⼆楼:201,202,203....
...
有了房间号地址,就能提高效率,外卖小哥就可以快速的通过房间号地址找到你,就不凉凉了~
如果把上面的例子对照到计算机中,又是怎么样呢?
计算机中 CPU 在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中
。而且我们买手机的时候,手机上内存有 128GB/256GB/512GB 等,这些内存空间如何高效的分配使用呢?
其实也是把内存划分为⼀个个的内存单元
,每个内存单元的大小取 1 个字节。
2、内存存储单位(补充)
计算机中常见的内存存储单位如下:
bit(比特位)、byte(字节)、KB、MB、GB、TB、PB
其中⼀个比特位可以存储⼀个二进制的位( 1 或者 0)。
各自换算关系如下:
1byte = 8bit
1KB = 1024byte
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
1PB = 1024TB
3、一切都是地址(了解)
3.1、CPU 怎么执行代码
C 语言用变量来存储数据,用函数来定义一段可以重复使用的代码,它们最终都要放到内存中才能供 CPU 使用。
数据和代码都以二进制的形式存储在内存中
,计算机无法从格式上区分某块内存到底存储的是数据还是代码。当程序被加载到内存后,操作系统会给不同的内存块指定不同的权限,拥有读取和执行权限的内存块就是代码,而拥有读取和写入权限(也可能只有读取权限)的内存块就是数据
。
CPU 只能通过地址来取得内存中的代码和数据
,程序在执行过程中会告知 CPU 要执行的代码以及要读写的数据的地址。如果程序不小心出错,或者开发者有意为之,在 CPU 要写入数据时给它一个代码区域的地址,就会发生内存访问错误。这种内存访问错误会被硬件和操作系统拦截,强制程序崩溃,程序员没有挽救的机会。
CPU 访问内存时需要的是地址,而不是变量名和函数名!变量名和函数名只是地址的一种助记符,当源文件被编译和链接成可执行程序后,它们都会被替换成地址。编译和链接过程的一项重要任务就是找到这些名称所对应的地址。
3.2、举例
假设变量 a、b、c 在内存中的地址分别是 0X1000、0X2000、0X3000,那么加法运算 c = a + b;
将会被转换成类似下面的形式:
0X3000 = (0X1000) + (0X2000);
( )
表示取值操作,整个表达式的意思是:取出地址 0X1000 和 0X2000 上的值,将它们相加,把相加的结果赋值给地址为 0X3000 的内存。
3.3、后话
变量名和函数名为我们提供了方便,让我们在编写代码的过程中可以使用易于阅读和理解的英文字符串,不用直接面对二进制地址,否则都是地址的场景简直让人崩溃。
需要注意的是:虽然变量名、函数名、字符串名和数组名在本质上是一样的,它们**
都是地址的助记符
**,但在编写代码的过程中,我们认为变量名表示的是数据本身
,而函数名、字符串名和数组名
表示的是代码块
或数据块的首地址
。
4、地址再理解
计算机中所有的数据都必须放在内存中,不同类型的数据占用的字节数不一样
。例如: int 占用 4 个字节,char 占用 1 个字节。
为了正确地访问这些数据,必须为每个字节都编上号码,就像门牌号、身份证号一样,每个字节的编号是唯一的,根据编号可以准确地找到某个字节。
下图是 4G 内存中每个字节的编号
(以十六进制表示):
每个内存单元也都有⼀个编号(这个编号就相当于学生宿舍房间的⻔牌号),有了这个内存单元的编号,CPU 就可以快速找到⼀个内存空间。
其中每个内存单元,相当于⼀个学生宿舍,⼀个字节空间⾥面能放 8 个比特位,就好比同学们住的八⼈间,每个⼈是⼀个比特位。
生活中我们把⻔牌号也叫地址
,在计算机中我们把内存单元的编号称为地址
。
所以我们可以理解为:内存单元的编号 == 地址
5、变量的地址
理解了内存和地址的关系,我们再回到 C 语⾔,创建变量其实就是向内存申请空间
!
如下代码:
#include <stdio.h>
int main()
{
int a = 10;
return 0;
}
详细解释:
上述的代码就是创建了整型变量 a,内存中申请 4 个字节
,用于存放整数 10,其中每个字节都有地址
,上图中 4 个字节的地址分别是:0x006FFD70、0x006FFD71、0x006FFD72、0x006FFD73
。
6、取地址操作符(&)
那我们如何能得到 a 的地址呢?
正如上面所知道的,每一个变量都有一个内存位置
,可使用 &
操作符
访问地址,它表示了在内存中的一个地址。
代码如下:
#include <stdio.h>
int main()
{
int a = 10;
printf("%p\n", &a); //取出a的地址
return 0;
}
按照我上面画图的例子,会打印处理:0x006FFD70
。
因此:
&a 会取出的是 a 所占 4 个字节中地址较小字节的地址
;%p 是指针占位符
,在 (2.8)输入 & 输出语句(1)章节有提及。
较小字节的地址还是较大字节的地址这个取决于你的设备是大端字节序还是小端字节序。这个在我飞书系统的知识点有说明。
《小菜狗 C 语言入门 + 进阶笔记》目录:《小菜狗 C 语言入门 + 进阶笔记》(0)简介
每日一更!
公众号、优快云等博客:小菜狗编程笔记
谢谢点赞关注哈!目前在飞书持续优化更新~
日更较慢有需要完整笔记请私我,C/C++/数据结构-算法/单片机51-STM32-GD32-ESP32/嵌入式/Linux操作系统/uboot/Linux内核-驱动-应用/硬件入门-PCB-layout/Python/后期小程序和机器学习!