前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《C陷阱与缺陷》之“语义”陷阱——数组越界导致的程序死循环问题

《C陷阱与缺陷》之“语义”陷阱——数组越界导致的程序死循环问题

作者头像
YIN_尹
发布2024-01-23 15:34:40
1750
发布2024-01-23 15:34:40
举报
文章被收录于专栏:YIN_尹的博客YIN_尹的博客

一.问题引入

我们先来一起看一段代码,思考一下它运行的结果可能是什么?

代码语言:javascript
复制
#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,x86环境下)

在这里插入图片描述
在这里插入图片描述

我们用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.局部变量是定义在栈区的,栈区内存的使用习惯是先使用高地址处的空间,再使用低地址处的空间(当然不同的环境下可能情况就有所不同,我们这里(vs2022-x86环境)是这样的) 2.而数组元素的地址随着下标的增加而增加(这个是确定的) 3.所以数组元素在向后越界访问(访问的地址逐渐变高)的时候,就有可能访问到i,因为i比数组先创建 4.一旦访问到i并将i置成0,就会发生死循环

在这里插入图片描述
在这里插入图片描述

在visual studio 2022/2013/2019上,i 和数组 arr 之间都是隔了2个整型的空间(即数组越界2个整型就访问到了i),但i 和数组 arr 之间隔多大空间是取决于编译器的,不同的编译器可能有所差异:

1. visual studio 2022/2013/2019上,i 和数组 arr 之间隔了2个整型的空间 2. vc 6.0上, i 和数组 arr 之间没有多余的空间 3. gcc上,i 和数组 arr 之间隔了1个整型的空间

当然:

我们上面说了栈区内具体到底是先使用低地址还是高地址,不同的环境下可能是不一样的情况,取决于操作系统与 CPU 的组合。 比如,就还是在vs2022上,其实在x64或者release版本下它就不遵循这个规则了,结果就不是死循环了

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

那上面我们解释了这个程序出现死循环的原因,当然决定这种结果有一个重要的原因就是我们把 i 定义在了数组 arr 之前,所以它的地址更高,因此数组向后越界才会访问到 i。

如果我们将 i 定义在数组 arr 之后,就不会访问到 i 了,也就不会死循环了。

代码语言:javascript
复制
#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节 ):

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

以上就是对该问题(出自《C陷阱与缺陷》第3章“语义”陷阱 的第6节 )的全部讲解欢迎大家指正!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-11-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.问题引入
  • 二.问题分析
  • 三.原理解释
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档