目录
C语言Segmentation fault (coredump)解决
C语言Segmentation fault (coredump)解决
将一个用C++写的学生信息管理系统修改为C语言版本,在编译运行时,报错Segmentation fault (coredump),然后通过gdb调试逐步找到原因:函数调用时,传的指针传错了,需要传入二级指针。做个错误记录。
概念:
1. C++中指针和引用
-
引用是C++中的概念
-
指针传递参数本质上是 值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的 实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。
-
引用传递过程中, 被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间 接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
-
引用传递和指针传递是 不同的,虽然它们都是在被调函数栈空间上的一个局部变量,但是任何对于引用参数的处理都会通过一个间接寻址的方式操作到主调函数中的相关变量。而对于指针 传递的参数,如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量。如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的 指针,或者指针引用。
2. C中的形参和实参
形参:在定义函数时,函数名后面括号中的变量名称为“形参”。在函数调用之前,传递给函数的值被复制到这些形参中
实参:在调用一个函数时,也就是真正使用一个函数时,函数名后面括号中的参数为“实参”。函数的调用者提供给函数的参数叫是实参。实参是表达式计算的结果,并且被复制给函数的形参
错误代码示例
原C++程序对于链表初始化参数采用引用的方式void InitLNode(LinkList &L)
,而我只是将程序修改为void InitLNode(LinkList L)
,这样使用这个函数的时候影响不到主函数的相关变量。我将错误程序简化成如下:
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{ //声明结点的类型和指向结点的指针类型
int data; //结点的数据域
struct LNode *next; //结点的指针域
}LNode,*LinkList; //LinkList为指向结构体Lnode的指针类型
void InitLNode(LinkList L) //初始化链表
{
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
L->data=0;
}
//尾插法增加节点
void NodeTailAdd(LinkList L,int a) //L是链表,a是新增节点的数据域
{
//要插入一个节点,首先需要申明一个节点空间用于存储e
//申明一个LNode类型的指针q,申明一段LNode大小的空间,并让q指向这段空间
LinkList q=(LinkList)malloc(sizeof(LNode));
q->data=a; //传递新增节点的数据域
q->next=NULL; //尾节点指NULL
LinkList p = L; //申明一个指针变量p指向链表的头部
while(p->next) //通过while循环将p逐步更新,直到p -> next为空,此时p指向链表尾部的节点
p=p->next;
p->next=q; //用q来更新p -> next实现节点的尾部插入。
}
int main()
{
int a=0;
LinkList L;
InitLNode(L);
NodeTailAdd(L,a);
return 0;
}
通过gdb调试这个程序,在运行到while(p->next)
会报Segmentation fault (coredump),然后从头开始追变量值,发现经过InitLNode()
出来后,p->next的值并没有等于NULL。然后就造成了后续的内存操作不当造成的,如:空指针、野指针(即多个指针指向一块内存,free掉一个指针之后,别的指针就成了野指针)的读写操作。
通过将void InitLNode(LinkList &L)
修改为如下:
void InitLNode(LinkList *L)
{
*L=(LinkList)malloc(sizeof(LNode));
(*L)->next=NULL;
(*L)->data=0;
}
修改后的完成程序:
#include<stdio.h>
#include<stdlib.h>
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
void InitLNode(LinkList *L)
{
*L=(LinkList)malloc(sizeof(LNode));
(*L)->next=NULL;
(*L)->data=0;
}
void NodeTailAdd(LinkList *L,int a)
{
LinkList q=(LinkList)malloc(sizeof(LNode));
q->data=a;
q->next=NULL;
LinkList p = (*L);
while(p->next)
p=p->next;
p->next=q;
}
int main()
{
int a=0;
LinkList L;
InitLNode(&L);
NodeTailAdd(&L,a);
return 0;
}