当前位置:网站首页>《C陷阱与缺陷》之“语义”陷阱——数组越界导致的程序死循环问题
《C陷阱与缺陷》之“语义”陷阱——数组越界导致的程序死循环问题
2022-08-07 08:00:00 【yin_尹】
一.问题引入
我们先来一起看一段代码,思考一下它运行的结果可能是什么?
#include <stdio.h>
int main()
{
int i = 0;
int arr[10] = {
1,2,3,4,5,6,7,8,9,10 };
for (i = 0; i <= 12; i++)
{
arr[i] = 0;
printf("hehe\n");
}
return 0;
}
我们先来简单分析一下这段代码:
我们可以看出来这段代码是通过一个for循环对数组的元素进行遍历重新赋值为0,但是我们很容易发现这段代码在访问数组时越界了,数组只有10个元素,第10个元素的下标应该是9,但是我们访问的下标i却是0~12;我们想到的结果可能是:
1.编译器直接报错(因为数组越界访问了)
2. 不报错的话,循环12次,打印12个"hehe"。
但是结果会和我们想象的一样吗?我们运行一下看看(这里使用的编译器是visual studio 2022)
我们用visual studio 2022运行该代码,程序陷入了死循环,为什么会出现这样的结果呢?
二.问题分析
下面我们通过调式来观察一下,导致死循环的原因是什么:
那么既然在调试过程中,i 的值和 arr[12] 的值一直相等,我们猜想,i 和 arr[12] 是不是处在同一块内存空间上。
我们继续调试看一看:
所以,现在我们就大概明白了,因为arr[12]和i的地址时相同的,所以我们访问arr[12]并把他赋值为0 时,i的值也变成了0,这样i的值一旦增加到12,就会变成0,永远不会大于12,因此for循环永远不会结束,陷入了死循环。
那为什么会这样呢,为啥数组越界会访问到i呢?
三.原理解释
现在我们就给大家解释一下,为什么会这样?为啥数组越界会访问到i呢?
之前的文章里提到过,一般来说,内存分为栈区,堆区和静态区。
而我们在这里创建的变量i,还有数组arr,它们都是局部变量
1.局部变量是定义在栈区的,栈区内存的使用习惯是先使用高地址,再使用低地址
2.而数组元素的地址随着下标的增加而增加
3.所以数组元素在向后越界访问(访问的地址逐渐变高)的时候,就有可能访问到i,因为i比数组先创建
4.一旦访问到i并将i置成0,就会发生死循环

在visual studio 2022/2013/2019上,i 和数组 arr 之间都是隔了2个整型的空间(即数组越界2个整型就访问到了i),但i 和数组 arr 之间隔多大空间是取决于编译器的,不同的编译器可能有所差异:
- visual studio 2022/2013/2019上,i 和数组 arr 之间隔了2个整型的空间
- vc 6.0上, i 和数组 arr 之间没有多余的空间
- gcc上,i 和数组 arr 之间隔了1个整型的空间
这就是这个程序出现死循环的原因,当然决定这种结果有一个重要的原因就是我们把 i 定义在了数组 arr 之前,所以它的地址更高,因此数组向后越界才会访问到 i。
如果我们将 i 定义在数组 arr 之后,就不会访问到 i 了,也就不会死循环了。
#include <stdio.h>
int main()
{
int arr[10] = {
1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i = 0; i <= 12; i++)
{
arr[i] = 0;
printf("hehe\n");
}
return 0;
}

这样打印12个“hehe”之后,编译器就直接报错了,程序就挂掉了。
以上就是对该问题(出自《C陷阱与缺陷》第3章“语义”陷阱 的第6节 )的全部讲解,欢迎大家指正!!!
边栏推荐
猜你喜欢

哈希-闭散列

别看了,这就是你的题呀(二)

如何配置百度地图应用访问白名单

Actionformer: Localizing moments of actions with transformers 论文阅读笔记

jenkins配置自动打包

VoLTE Basic Self-Learning Series | What is Forking in SIP and IMS

The fifth bullet of FPGA development: hand rubbing breathing light code

OC-run loop

JVM:(五)运行时数据区之虚拟机栈

Web网页端IM产品RainbowChat-Web的v4.1版已发布
随机推荐
The second bullet of FPGA development: running water lamp experiment
The number of [NOIP2001 improve group] division
【n-piece chess】
服务端获取用户ip
ASEMI整流桥GBL610参数,GBL610尺寸,GBL610特征
RestTemplate
Swordsman Offer II 091. Paint the House
30.01 C/S、TCP/IP协议妙趣横生、惟妙惟肖谈
The fifth bullet of FPGA development: hand rubbing breathing light code
[Promise] Promise use / callback hell problem async-await / macro queue and micro queue
力扣:494. 目标和
30.01 C/S and TCP/IP protocols are interesting and vivid
C 学生管理系统_读取文件中得学生信息
Abaqus2019的abaqus_v6.env在哪里
HPC Technology: Analysis of MPICH Implementation Principle
5.PHPwhile,foreach和for循环
【IO复用】select(处理读/写/异常事件)
神经网络和pid有什么区别,基于神经网络的pid控制
接口流量突增,如何做好性能调优?
路由、 网络、互联网、因特网、公网私网IP、NAT技术