一句话类比

内存就像一个巨大的公寓楼,每个房间都有一个唯一的门牌号(地址),房间里可以住一个字节的数据(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 为例)

地址小端序大端序
0x10000x780x12
0x10010x560x34
0x10020x340x56
0x10030x120x78
  • 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 ],采用小端序,写出每个字节的值。

  1. 第一个 int: 0xAABBCCDD → 字节分解(从低到高):0xDD, 0xCC, 0xBB, 0xAA

    • 地址 0x2000: 0xDD
    • 地址 0x2001: 0xCC
    • 地址 0x2002: 0xBB
    • 地址 0x2003: 0xAA
  2. 第二个 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?

自测题答案:

  1. 小端序下最低字节在最低地址:0x1000=0x78, 0x1001=0x56 → 答案为 0x56。
  2. 32位指针占4字节,可表示 2^32 字节 = 4GB。
  3. p+3 → 0x2003;q+3 → 0x2000 + 3*4 = 0x200C。
  4. 地址 0 通常被操作系统保留为无效地址,访问它会产生异常(段错误),用于表示“不指向任何对象”。

模拟练习答案(大端序下地址0x2000字节):第一个int大端序:0x2000=AA, 0x2001=BB, 0x2002=CC, 0x2003=DD;第二个int:0x2004=11, 0x2005=22, 0x2006=33, 0x2007=44。所以 0x2000 = 0xAA。