做题中踩到的一些坑
在我的blog中查看:https://www.yeliheng.com/p/bb4fbbb5.html#more
[踩坑记录]对C编译器SegmentFault 11问题的思考及解决
前几天做到一道Mc插火把的题目(可能有些同学做过),需要开一个二维数组,题目没有给数组的范围,于是我就随意地写了一个5000,没想到问题就这么出现了。
在我使用gcc编译时,编译器并没有抛出异常,但运行的时候异常发生了。
报了一个 SegmentFault 11 的错误,并没有指出具体哪行出了错,令人匪夷所思。于是我打开了VScode进行调试。单步调试的过程中我发现当程序执行到main函数中异常被触发,如图所示。
从address我判断可能是内存地址分配错误导致的问题。但哪个地方会导致问题的发生呢?
问题初步分析
从编译器的角度讲,每定义一个新变量,编译器就会为其开辟一块内存空间,并有内存地址与其对应。所以问题应该就出现在变量的定义了。从我写的代码上看,只有数组需要为其开辟大小,其他均不用。问题很可能就在于我对二维数组的定义上。我尝试着缩小其范围,从5000缩小到2000,问题还是没有得到解决。我又再次将其缩小到1000,问题莫名其妙解决了。
深入分析
程序虽然正常运行,并被评测系统AC,但要问题还是没有真正解决,因为我并不知道其原因所在。Google大法好,我上Google搜寻了一波,终于从本质上弄懂问题。
开始分析:
在弄清楚问题之前需要了解堆栈的概念,相信大家不会陌生,这里引用百度百科上的基本定义
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
对于每个进程或线程来说,栈空间大小是有限的,而局部变量的内存是在栈上分配的,如果局部变量过大,则会出现分配失败的情况,也就是栈溢出。就好比一个桶只能装下5个苹果,在放第六个的时候就掉出来了。
解决之道
方法应该有很多,我了解到以下两种方法
1.把数组定义为全局变量
原因:全局变量分配时,会分配在全局变量空间,不受栈空间大小影响。
2.手动分配动态内存空间
通过malloc,calloc, zalloc等函数,可以分配动态内存空间。该空间会分配在堆上,同样不受栈空间的限制。代码会稍复杂。
END 之后就不会再跳进相同的坑里啦