1、数组越界” (ABOB)
“数组越界”指的是当访问数组时,索引超出了数组的有效范围。通常发生在以下情况,索引小于 0
。索引大于或等于数组的大小。如有一个大小为10
的数组,有效的索引是从0
到9
。如果你访问了数组的索引为10
或更高,或者是负数,这就是越界访问。
#include <stdio.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; // 正确的访问方式 for (int i = 0; i < 5; i++) { printf("arr[%d] = %d\n", i, arr[i]); } // 错误的访问方式(越界访问) // printf("%d\n", arr[5]); // 这是越界的,因为有效的索引是 0 到 4 return 0; }
2、 访问越界的内存
C和C++中,访问越界的数组会导致未定义行为。也就是可能会:崩溃(例如,发生段错误),返回一个意外的值(垃圾数据或错误数据),看起来正常工作,但导致难以察觉的bug,损坏内存,导致程序后续发生其他错误。访问数组越界后的行为是没有保障的,程序的表现可能会因编译器、系统架构或错误发生的上下文而有所不同。
#include <stdio.h> int main() { int arr[5] = {1, 2, 3, 4, 5}; // 访问越界的索引 printf("%d\n", arr[100]); // 未定义行为:访问越界的索引 return 0; }
3、数组越界是未定义的原因
C和C++中,数组没有自动进行边界检查。也就意味着,语言本身或编译器不会强制检查数组越界。虽然可能希望在访问越界索引时程序抛出错误,但编译器通常不会检查数组边界,以避免性能开销。语言标准明确将越界访问定义为未定义行为。这是为了优化性能和提供更大的灵活性。
#include <iostream> using namespace std; int main() { int arr[5] = {1, 2, 3, 4, 5}; // 正常访问数组元素 // 输出 arr[2],即 3 cout << "arr[2]: " << arr[2] << endl; // 越界访问 // 未定义行为,访问数组边界外的内存 cout << "arr[10]: " << arr[10] << endl; return 0; }
4、常见的数组越界错误
访问数组越界后,可能会出现垃圾数据,返回的值可能是随机或垃圾数据。段错误(崩溃),如果访问的地址完全无效(例如,超出了已分配的内存空间),程序可能崩溃。内存损坏,如果越界访问修改了其他变量或结构体使用的内存,可能会导致数据损坏,从而在程序后续发生错误。
#include <stdio.h> int main() { // 定义一个长度为3的整数数组 int arr[3] = {1, 2, 3}; // 越界访问,尝试访问 arr[10] arr[10] = 100; // 这将写入 arr[10],但 arr 只有 3 个元素,越界写入会导致未定义行为,可能损坏内存 // 打印 arr[0],其值可能由于上面的内存损坏而被更改 printf("arr[0] = %d\n", arr[0]); return 0; }
5、防止越界访问
尽管C和C++默认不会自动检查数组边界,但可以采取一些措施来防止越界错误。
1)手动检查数组边界
在访问数组之前,确保索引在有效范围内。
#include <stdio.h> int main() { int arr[] = {10, 20, 30, 40, 50}; int size = sizeof(arr) / sizeof(arr[0]); int index = 2; // 假设用户输入的索引 if (index >= 0 && index < size) { printf("数组元素: %d\n", arr[index]); } else { printf("索引越界!\n"); } // 测试索引越界的情况 index = 5; // 索引超出数组范围 if (index >= 0 && index < size) { printf("数组元素: %d\n", arr[index]); } else { printf("索引越界!\n"); } return 0; }
2)使用C++中的std::vector
与数组不同,C++中的
使用at()方法进行边界检查(如果索引越界会抛出异常)。std::vector
#include <iostream> #include <vector> #include <stdexcept> // for std::out_of_range using namespace std; int main() { // 创建一个整数类型的vector vector<int> vec = {1, 2, 3}; try { // 尝试访问vec中不存在的元素(越界) // 会抛出std::out_of_range异常 cout << vec.at(5) << endl; } catch (const std::out_of_range& e) { // 捕获异常并打印错误信息 cout << "越界错误: " << e.what() << endl; } return 0; }