问题历史:
指针算术在 C 语言中出现是为了有效地操作内存、数组和结构体。它与内存寻址紧密相关,以及 C 如何在最低级别上工作——对指针进行加减可以访问数组中的连续元素。
问题:
主要的困难在于,指针算术与数字算术并不等同:对指针增加 1 会根据它所指向的类型大小来增加其值。经典错误包括超出分配数组的边界、操作不兼容类型的指针以及尝试与 void * 进行计算。
解决方案:
在操作指针时,总是要考虑类型大小,避免与 void* 的代数计算,控制数组的边界。访问数组元素时,使用索引或计算指针,并事先检查边界。
代码示例:
#include <stdio.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; int *p = arr; printf("%d\n", *(p + 2)); // 3 // 不合法:p + 10 超出数组边界 return 0; }
关键特点:
可以将浮点类型的值或其他类型的变量加到指针上吗?
不可以,指针只能加减整数类型的值。使用浮点数将导致编译错误。
即使 i 超出数组边界,*(arr + i) 和 arr[i] 是否总是相同的?
不。它们在语义上是等价的,但如果索引超出数组边界,这两个表达式都会导致未定义行为(undefined behavior)。
从指向不同数组的指针中减去会发生什么?
结果在标准中未定义,并被视为错误。只能减去位于同一数组(或同一分配块内存)中的指针。
buffer overrun)在代码中,开发人员使用指针算术遍历数组:
优点:
缺点:
在重构版本中,每一步都使用显式的边界检查:
优点:
缺点: