vs编写c语言代码时存在的数组越界但可打印越界值现象
环境 vs MSVC x86 Debug
代码
define _CRT_SECURE_NO_WARNINGS
include <stdio.h>
int main()
{
int score[2];
int select = 0, count = 0;
do
{
printf("\n");
printf("1.输入成绩(-1 结束输入)\n");
printf("2.打印所有成绩\n");
printf("3.计算平均分\n");
printf("4.获取最高成绩\n");
printf("5.退出\n");
printf("\n");
scanf("%d", &select);
switch (select)
{
case 1:
{
for (int i = 0; ; i++)
{
int num = 0;
scanf("%d", &num);
if (num == -1)
{
break;
}
else
{
score[count++] = num;
}
}
}
break;
case 2:
{
for (int i = 0; i < count; i++)
{
printf("%d ", score[i]);
}
}
break;
case 3:
{
int total = 0;
for (int i = 0; i < count; i++)
{
total += score[i];
}
printf("%.3f", (float)total / count);
}
break;
case 4:
{
int max = 0;
for (int i = 0; i < count; i++)
{
if (max < score[i])
{
max = score[i];
}
}
printf("最大值: %d ", max);
}
break;
default:
printf("输入错误");
break;
}
} while (select != 5);
}
现象
1.输入成绩(-1 结束输入)
2.打印所有成绩
3.计算平均分
4.获取最高成绩
5.退出
1
1 2 55 66 -1
1.输入成绩(-1 结束输入)
2.打印所有成绩
3.计算平均分
4.获取最高成绩
5.退出
2
1 2 55 66 ==========
1.输入成绩(-1 结束输入)
2.打印所有成绩
3.计算平均分
4.获取最高成绩
5.退出
产生问题:数组明显越界但值仍能输入和输出且编译器未报错
直到程序退出 才会产生异常
异常输出明细

异常解释:
- C 语言不会对数组越界进行运行时检查
在 C 语言中,数组访问不会进行边界检查。当程序执行类似:
score[count++] = num;
且 count 超过数组实际容量时,程序仍然会继续执行,而不会立即报错。
这是因为数组越界在 C 标准中属于未定义行为(Undefined Behavior),编译器和运行时系统不保证对其进行检测或阻止。
2.栈内存是连续分配的
局部变量(如数组、普通变量等)通常存储在栈上,它们在内存中是连续分布的。
因此,当发生数组越界时,程序实际写入的并不是“非法区域”,而是:
相邻的局部变量
栈上的填充数据
或尚未被使用的栈空间
这就导致越界写入在短时间内不会立即触发崩溃或异常表现。

3.写入越界不会立刻报错
在当前 MSVC x86 Debug 环境下,运行时并不会在每一次内存写入时都进行严格边界检测。
因此,即使发生越界写入:
程序仍可能继续正常运行
数据看似正常输出
错误不会立即暴露
但此时程序的内存已经被破坏

4.局部变量生命周期结束不会自动检测越界
C 语言不会在变量生命周期结束时自动检查其是否发生越界访问。
因此,即使数组已经被破坏:
程序在运行过程中仍可能表现正常
错误不会在“变量作用域结束”时被主动发现

5.错误可能在后续阶段才显现
由于越界写入破坏了栈结构或覆盖了关键数据,真正的错误可能不会立即出现,而是在后续阶段才被触发,例如:
函数返回时
栈帧销毁时
MSVC 的栈保护机制检测阶段
当运行时检测到栈结构被破坏时,就会抛出类似:
Stack around the variable 'score' was corrupted
的异常提示。

结论:
数组越界属于 C 语言中的未定义行为,其错误检测依赖于编译器和运行时环境。
在 MSVC Debug 模式下,由于栈保护机制的存在,越界错误通常不会立即暴露,而是可能在函数返回或栈检查阶段才被检测到。
因此:
C 语言将内存安全的责任交由程序员自行管理,这也是其高性能与低抽象开销的设计特点之一。

浙公网安备 33010602011771号