1. 数组与指针的本质差异
在C/C++开发中,新手最常混淆的概念莫过于数组和指针。表面上看,它们都能通过下标访问元素,甚至在某些情况下可以互换使用,但这两种数据结构在内存模型和操作语义上存在根本性区别。
数组是连续内存块的具名表示,编译器在编译期就能确定其内存布局。例如声明int arr[5]时,系统会立即分配20字节连续空间(假设int为4字节),arr这个标识符直接绑定到这段内存的首地址。而指针本质是存储地址的变量,声明int *ptr仅分配了指针本身的空间(通常4或8字节),它指向的内存需要额外分配。
关键区别:数组名是地址常量(右值),指针是地址变量(左值)。这意味着
arr = ptr这样的赋值是非法的,而ptr = arr完全合法。
2. 内存访问机制的底层解析
2.1 数组的访问原理
当使用arr[i]访问数组元素时,编译器生成的指令是:
- 取数组首地址(编译期已知)
- 加上偏移量
i*sizeof(element_type) - 直接解引用目标地址
这种访问方式不涉及任何运行时地址计算,效率极高。反汇编后通常对应一条MOV指令,例如:
assembly复制mov eax, [arr+4*i] ; 假设arr在eax寄存器
2.2 指针的访问原理
指针访问ptr[i]的处理流程更复杂:
- 从指针变量所在地址加载当前存储的地址值
- 加上偏移量计算
- 最后解引用
对应的汇编可能如下:
assembly复制mov ebx, [ptr] ; 先加载指针值
mov eax, [ebx+4*i] ; 再解引用
多出的内存访问层级会导致轻微性能开销,在循环密集场景可能产生显著差异。
3. 典型场景中的行为对比
3.1 sizeof运算的差异
c复制int arr[5];
int *ptr = arr;
printf("%zu %zu", sizeof(arr), sizeof(ptr));
在64位系统输出为20 8。数组的sizeof返回整个数组的字节数,而指针的sizeof永远返回指针类型的大小。
3.2 函数参数传递的退化
当数组作为函数参数时,会发生"数组到指针"的隐式转换:
``
