一句话类比
内存就像一个巨大的公寓楼,每个房间都有一个唯一的门牌号(地址),房间里可以住一个字节的数据(8个比特)。
什么是内存?
计算机的内存(RAM)是一长排存储单元,每个单元可以保存一个字节(8位二进制数)。为了找到某个字节,CPU需要知道它的“门牌号”,这个门牌号就是内存地址。
关键点
- 每个地址对应 1个字节(即使是64位计算机,按字节编址)。
- 地址是一个非负整数,通常用十六进制表示(如
0x2000)。 - 地址范围决定了能访问的内存大小:32位地址最多
2^32 = 4GB,64位地址极大(实际使用48位或57位)。
地址空间与数据存放
想象一排连续的编号格子:
地址: 0x1000 0x1001 0x1002 0x1003
数据: [ 12 ] [ 34 ] [ 56 ] [ 78 ]
- 整数
0x12345678在内存中占用4个字节(地址0x1000~0x1003)。 - 但存放顺序有两种方式:大端序(高字节在低地址)和小端序(低字节在低地址)。
小端序 vs 大端序(以 0x12345678 存储在 0x1000 为例)
| 地址 | 小端序 | 大端序 |
|---|---|---|
| 0x1000 | 0x78 | 0x12 |
| 0x1001 | 0x56 | 0x34 |
| 0x1002 | 0x34 | 0x56 |
| 0x1003 | 0x12 | 0x78 |
- x86 / x86-64 使用小端序(你会在VS反汇编中常见)。
- ARM / RISC-V 通常支持两种模式,但大多数操作系统使用小端序。
- 网络协议(TCP/IP)使用大端序(称为“网络字节序”)。
如何阅读内存地址(在调试器中)
当你用Visual Studio或GDB调试C++代码时,经常看到类似这样的输出:
&myVar = 0x00AFFB8C
0x00AFFB8C就是变量myVar的起始地址。- 观察该地址附近的字节,可以查看原始内存内容。
指针与地址
C++中的指针就是保存地址的变量:
int x = 42;
int* p = &x; // p 中存的是 x 的地址汇编指令中,[rax] 表示 rax寄存器中的数值作为地址,去内存中读取数据。这与“门牌号”类比完全一致。
模拟练习:手动解析内存布局
题目:假设从地址 0x2000 开始存放一个 int 数组 [ 0xAABBCCDD, 0x11223344 ],采用小端序,写出每个字节的值。
-
第一个 int:
0xAABBCCDD→ 字节分解(从低到高):0xDD,0xCC,0xBB,0xAA- 地址 0x2000: 0xDD
- 地址 0x2001: 0xCC
- 地址 0x2002: 0xBB
- 地址 0x2003: 0xAA
-
第二个 int:
0x11223344→ 字节:0x44,0x33,0x22,0x11- 地址 0x2004: 0x44
- 地址 0x2005: 0x33
- 地址 0x2006: 0x22
- 地址 0x2007: 0x11
自己尝试:如果改为大端序,上述地址 0x2000 的字节是什么?
(答案在文末)
真实世界例子
- 数组遍历:
arr[i]的地址 =arr地址 + i * sizeof(元素)。 - 结构体成员:
&(obj.field)计算偏移量,访问该地址。 - 空指针异常:试图访问地址
0x00000000(或很小的地址)会触发段错误。 - 栈地址:局部变量的地址通常在高地址(栈向低地址增长),例如
0x7FFFFFFF附近。
自测题
- 1. 假设小端序机器,地址
0x1000处存放一个 int 值0x12345678,那么地址0x1001处的字节值是多少? - 2. 一个 32 位指针变量本身占几个字节?它能够表示的地址范围是多少 GB?
- 3. 在 C++ 中,
char* p = (char*)0x2000; p += 3;后 p 的地址是多少?如果换成int* q = (int*)0x2000; q += 3;地址又是多少? - 4. 为什么空指针 (nullptr) 通常被定义为地址 0?
自测题答案:
- 小端序下最低字节在最低地址:0x1000=0x78, 0x1001=0x56 → 答案为 0x56。
- 32位指针占4字节,可表示 2^32 字节 = 4GB。
- p+3 → 0x2003;q+3 → 0x2000 + 3*4 = 0x200C。
- 地址 0 通常被操作系统保留为无效地址,访问它会产生异常(段错误),用于表示“不指向任何对象”。
模拟练习答案(大端序下地址0x2000字节):第一个int大端序:0x2000=AA, 0x2001=BB, 0x2002=CC, 0x2003=DD;第二个int:0x2004=11, 0x2005=22, 0x2006=33, 0x2007=44。所以 0x2000 = 0xAA。