通常导致段错误的几个直接原因:
(1)解除引用一个包含非法值的指针
(2)解除引用一个空指针(常常由于从系统程序中返回空指针,并未检验就使用)
(3)在未得到正确的权限时进行访问。例如,试图往一个只读文本段存储值就会引起段错误
(4)用完了堆栈或堆空间(虚拟内存虽然巨大但绝非无限)
以发生频率为序,最终可能导致段错误的常见编程错误是:
1. 坏指针值错误: 在指针赋值之前就用它来引用内存,或者向库函数传送一个坏指针。第三种可能导致坏指针 的原因是对指针进行释放之后再访问它的内容。可以修改free语句。在指针释放之后再将它置为空值。
free(p); p = NULL;
这样,如果在指针释放之后继续使用该指针,至少程序能在终止之前进行信息转储。
2. 改写(overweight)错误: 越过数组边界写入数据,在动态分配的内存两端之外写入数据,或改写一些堆管 理数据结构(在动态分配的内存之前的区域写入数据)
p = malloc(256); p[-1] = 0; p[256] = 0;
3. 指针释放引起的错误: 释放同一个内存块两次,或释放一块未曾使用malloc分配的内存,或释放仍在使用中的 内存,或释放一个无效的指针。一个极为常见的与释放内存有关的错误就是在 for(p = start; p; p = p->next) 这样的循环中迭代一个链表,并在循环体内使用free(p)语句。这样,在下一次循环迭代时,程序就会对已经释放的指针进行解除引用操作,从而导致不可预料的结果。
那如何在链表中释放元素呢?
在遍历链表时正确释放元素的方法是使用临时变量存储下一个元素的地址。这样就可以安全地在任何时候释放当前元素,不必担心在取下一个元素的地址时还要引用它。代码如下:
struct node *p, *start, *tmp;
for(p = start; p; p = tmp){
tmp = p->next;
free(p);
}