越界访问是一种常见的程序错误,本篇文章将基于一个案例,从什么是数组越界,数组越界经常发生在什么地方,如何预防数据越界三方面来详细介绍该错误。
查看以下c语言代码,试写出其运行结果,并说明理由:
#include <stdio.h>
int main()
{
int i = 0;
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
for (i = 0; i <= 12; i++)
{
arr[i] = 0;//数组越界访问
printf("%d\t",i);
}
return 0;
}这个代码非常简洁,我们可以很容易的发现其中i的范围是1-12,但是arr数组的大小只有10个int类型,出现了越界访问。
我们在vs2022中,在debug、x86环境下,运行该代码,结果如下:

没错,出现了死循环。但是,为什么呢?
越界访问(Out-of-Bounds Access),也称为缓冲区溢出或越界读写,是一种常见的程序错误。它指的是程序试图访问超出其分配的内存空间的数据。这种行为可能会导致程序崩溃或者被利用来进行恶意攻击。
int arr[10];
for (int i = 0; i <= 10; i++) { // 错误:i <= 10
arr[i] = i;
}int arr[10];
int* ptr = arr;
ptr += 11; // 错误:ptr指向了数组范围之外
*ptr = 42; // 越界访问char dest[10];
char src[] = "Hello, World!";
strcpy(dest, src); // 错误:src长度超过dest的大小int* ptr = (int*)malloc(10 * sizeof(int));
free(ptr);
*ptr = 42; // 错误:ptr指向的内存已经释放int arr[10];
for (int i = 0; i < 10; i++) {
arr[i] = i;
}char dest[10];
char src[] = "Hello, World!";
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0'; // 确保字符串以null字符结尾int* ptr = NULL;
ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL) {
// 处理内存分配失败的情况
}if (ptr != NULL) {
*ptr = 42;
}free(ptr);
ptr = NULL;使用安全的字符串函数:使用如strncpy、strncat等安全的字符串操作函数,而不是strcpy、strcat等可能导致越界的函数。
char dest[10];
char src[] = "Hello, World!";
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0'; // 确保字符串以null字符结尾int* ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL) {
// 处理内存分配失败的情况
}free(ptr);
ptr = NULL;struct {
int a;
int b;
} s;
s.a = 10; // 正确
// s.c = 20; // 错误:结构体中没有成员cunion {
int a;
char b[4];
} u;
u.a = 0x12345678;
// 正确访问联合体成员我们在第八行添加一个断点,并对代码进行调试:

我们在监视窗口下,逐步观察值的变化:

可以看到,我们的前十次for循环是正常运行的:

那么问题就出现在数组越界后了,我们可以修改监视窗口,使得arr[10]、arr[11]、arr[12]也可以显示出来。

此时,我们可以发现,arr[10]、arr[11]是随机值,但是arr[12]储存了一个值。当我们执行到arr[12]被修改时,监视如下:

没错!i的值被改变了!那么我们可以猜测,i的值是否就是储存在arr[12]处?使用监视验证这个猜想:

答案出来了,可以看见arr[12]的地址和i的地址一模一样,即因为数组越界访问,使得i的值永远无法达到跳出循环的条件。
因此,出现了死循环现象。
通过本文的案例分析,我们深入探讨了数组越界访问这一常见错误。越界访问不仅会导致程序崩溃,还可能引发安全漏洞。本文从越界访问的定义、常见场景及预防方法三个方面进行了详细阐述。在案例中,通过调试,我们发现数组越界访问导致循环变量 i 的值被意外修改,从而引发死循环