[转载]一个指针参数引发的血案
来源:互联网 发布:淘宝助理搬家工具 编辑:程序博客网 时间: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中的函数存在很多陷阱,用的时候一定要时刻小心才是。
- [转载]一个指针参数引发的血案
- 一个指针的引用引发的血案
- 一个 * 引发的血案
- 一个“-”引发的血案
- 一个"/"引发的血案
- 一个Sqrt函数引发的血案(转载)
- 消息参数引发的血案
- 参数名引发的血案
- 一个松果引发的血案
- 一个memset引发的血案
- 一个包子引发的血案?
- 一个斜杠引发的血案
- 一个逗号引发的"血案"
- 一个static 引发的“血案”
- 一个分号引发的血案
- 一个key引发的血案
- 一个变量引发的血案
- 一个return引发的血案
- java虚拟机学习笔记
- 程序员职业规划哲理思想
- day day up
- Directx字体
- Java.lang.OutOfMemoryError是什么
- [转载]一个指针参数引发的血案
- 在C++的环境中使用C开发
- 判断回文字符
- 【转】c++ sprintf详解
- Java的内存泄漏
- 计算机总线概述
- JQuery收集
- 如何判断一个网络路径是不是有效路径
- 重载/覆盖/隐藏