【C语言的栈溢出问题以及部分解决】

本文探讨了C语言中的栈溢出问题,包括函数递归层次太深、局部变量体积过大、动态内存未释放、数组访问越界和指针非法访问等原因。提出了修改栈区空间大小、尾部递归优化等解决方案,并详细阐述了尾部递归的原理和编译器优化。同时,强调了数组越界和指针非法访问的危害,提醒程序员注意避免这些问题。
摘要由CSDN通过智能技术生成

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修改)
具体步骤:项目->属性->链接器->堆栈保留大小请添加图片描述

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

afool�‍♂️

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值