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;
}