C语言的栈溢出问题
例如:针对学习过程中遇到的栈溢出问题
前言
溢出,常见的解释是:程序外部的数据大小,超出其规定数据类型所能表达的范围,从而造成正常程序预期外的错误表达。 溢出一般被当做黑客攻击操作系统的途径。具体的溢出类型有以下三种:缓冲区溢出(Buffer overflow);内存溢出(memory overflow);数据溢出(data overflow)。 本文只谈及缓冲区溢出的——栈溢出
栈溢出(Stack overflow)
在谈栈溢出之前,先提一下一个程序所占用计算机内存的分布:
导致栈溢出的原因
一般导致栈溢出的原因有五点原因:
①函数递归层次太深。 递归函数在运行时会执行压栈操作,当压栈次数太多时,也会导致堆栈(栈)溢出。
②局部变量体积太大。 (因为局部变量是存储在栈中的)
③动态申请空间使用之后没有释放。 虽然程序中动态申请空间没有释放,在程序结束之后,系统也会将进程中申请的内存全部释放,但是程序运行中时间过长,导致内存占用过大,进程耗尽所有内存。申请后不手动释放就会内存泄露(C语言中是用malloc和free来分配空间和释放空间(内存)的)
④数组访问越界。 C语言中是没有提供数组下标越界检查,如果在程序中出现数组下标访问超出数组范围,就会出现内存访问错误 (例如进行字符串拷贝或处理用户输入等)
⑤指针非法访问。 指针保存了一个非法地址(其实也可以看做是指针越界),再通过指针访问所指向地址的时候就会出现内存错误。
此处我想提及学习过程中遇到的递归循环发生的系统栈溢出。
①函数递归层次太深
①函数递归层次太深
为了避开数据溢出的干扰,这里我选用了一个比较简单的加法运算来举例
int Fun(int n)
{
if (n == 1)
return 1;
else
return n + Fun(n - 1);
}
int main()
{
printf("%d\n", Fun(10000));
return 0;
}
在运行到第5211次(当然每一次都不确定,大约都是在5000次左右)的时候,直接就爆出Stack overflow(栈溢出)
那么这段程序在栈区干了些啥呢?就把人家弄爆了。(入栈,此程序还未出栈,以下只是补充画的出栈图)
递归层次太深,其实也是函数调用过多。函数调用的本质是:入栈(push)和出栈(pop),递归中每一次调用函数时,都会入栈保存一个栈帧,里面保存着该函数的调用信息、内部变量(后面简称这两玩意为“调用记录”),这样栈空间总有被耗干的时候。 此处的Fun函数就是如此,”被调用10000次,一直调用到5211次时还没到可以返回的时候,我们写的这个程序还没到出栈,栈空间就满了。并且我们发现,即使是栈没满的情况,程序正常运行,函数又往反方向一个一个的出栈,其实效率是很慢的。
1.修改栈区空间大小
解决问题①(函数递归层次太深)的方法还是挺多的,直接一点的就修改栈堆保留大小 ,它的默认是1MB,改大了就可以了。(此处针对VS修改)
具体步骤:项目->属性->链接器->堆栈保留大小