[转载]一个指针参数引发的血案

来源:互联网 发布:淘宝助理搬家工具 编辑:程序博客网 时间:2024/05/08 14:22

原文链接:http://blog.odichy.org/tag/malloc


今天在阅览室看《算法导论》,顺便用C写了链表相关的算法,结果在初始化链表的时候出现了问题,出现了Segmentation fault。先来看看错误的代码,省略一些定义了:

12345678910111213
int main(void)
{
list *li;
init(li);
insert(li, 5);
//main函数以下省略,insert为插入一个元素到链表
}
 
static void init(list *li)
{
li = (list *)malloc(sizeof(list));
//init函数以下省略
}

这个是想在一个方法里面初始化链表,因为malloc是在堆上分配内存,所以其分配的空间不会随函数的结束而从栈上消失,所以自然而然的想把这的值 直接给li,以便在接下来的程序中引用。但是编译执行时显示Segmentation fault,不用想肯定是main中的li仍然指向NULL。开始比较疑惑,因为一般来说传一个指针进去,是会改变其指向的内容的,就好象是面向对象中的 按引用调用一样,这里为什么会出错呢?如果把init函数的代码段移回main中,程序运行没什么问题的,那么肯定问题出在malloc分配的空间上。

分析一下这个程序执行的过程,首先声明一个list *类型的参数,也就是一个可以指向list类型的指针,因为还没赋值,所以其空间内存的数据可能是任何东西。然后就是调用init方法,注意此时所传递的 是main.li这个变量内存的值,因此对于init.li,其值是main.li的值,它只是main.li的一个拷贝,但是它的存储空间是分配在 init函数活动栈上的,因此此时将malloc分配的堆内存地址赋给init.li时只是改变了init活动栈上的li的值,并未真正去改变 main.li这个main的活动栈上的li的值。因此当init函数完成调用,返回后,其活动栈将销毁,也就是将我们刚刚malloc的那块堆内存地址 给销毁了,此时就造成了内存泄漏。而我们再通过main.li调用时,其实它还是没有分配过存储空间的,所以产生了Segmentation fault。

分析明白产生错误的原因后,自然就好改了,要么将malloc分配的指针返回,要么将参数改成一个指针的指针(即main.li的地址),按第二个方法更改程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
int main(void)
{
list *li;
init(&li);
insert(li, 5);
//main函数以下省略,insert为插入一个元素到链表
}
 
static void init(list **li)
{
*li = (list *)malloc(sizeof(list));
//init函数以下省略
}

由此可见,其实在指针做参数时,还是存在一定的陷阱的,如果不清楚程度堆栈的建立过程,很容易出现内存泄漏,而且在看不懂GAS汇编的情况下,要想通过二进制机器码分析出问题所在,还是有一定困难的。在C中的函数存在很多陷阱,用的时候一定要时刻小心才是。



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电脑上没有pdf怎么办 word转txt乱码怎么办 双珠卷发器怎么办用 pdf打印出来很小怎么办 热敏打印机无法打印怎么办 pdf格式不能打印怎么办 pdf文件没有打印怎么办 打印机添加不上怎么办 笔记本电脑收不到wifi怎么办 账套输出不了怎么办 无法加载pdf文档怎么办 pdf控件不可用怎么办 扫描件不清晰怎么办 图片大于200k怎么办 手机图片字模糊怎么办 天然气手册丢了怎么办 消消乐登录异常怎么办 新手想学考古怎么办 省份证改名字怎么办 文曲星放太久开不了机怎么办 小狗吃火腿肠皮怎么办 虚火引起的牙痛怎么办 牙髓炎怎么办立刻止疼 小蜜丸吃不下去怎么办 铜钱的字不认识怎么办 古钱币出手好烦怎么办 安装目录不可写怎么办 手机不支持exfat格式怎么办 windows7图标变大了怎么办 igs格式烂曲面怎么办 手机桌面文件夹打不开怎么办 苹果下载不了150怎么办 iphone6速度变慢怎么办 苹果手机微信打不开pdf怎么办 苹果手机打不开pdf怎么办 pdf文件超过了怎么办 pdf电脑删不了怎么办 联想笔记本摄像头横屏调竖屏怎么办 pdf文件打开失败怎么办 pdf复制文字乱码怎么办 电子发票乱码了怎么办