我正在为双向链表编写C程序。以下代码仅包含main
函数和insert
函数。
cfile.c
/*
In the following code doubly linked list is implemented
*/
//header files
#include <stdio.h>
#include <stdlib.h>
//create structure for node
struct node{
int info;
struct node *LChild;
struct node *RChild;
}*start;
typedef struct node *NODE;
//function to insert data in the list
void insert(){
int data;
NODE q, temp;
temp = (NODE)malloc(sizeof(struct node));
if(temp){
printf("\nEnter the data to be inserted in the list: ");
scanf("%d", &data);
temp->info = data;
temp->RChild = NULL;
}
else{
printf("Out of memory.");
return;
}
if(start == NULL){
temp->LChild = NULL;
start->LChild = temp;
start = temp;
}
else{
q = start;
while(q->RChild != NULL){
q = q->RChild;
}
q->RChild = temp;
temp->LChild = q;
}
return;
}
//function to insert at the begining
void insert_at_beg(){
int data;
NODE temp;
temp = (NODE)malloc(sizeof(struct node));
if(temp){
printf("\nEnter the data to be inserted at the beginning of the list: ");
scanf("%d", &data);
temp->info = data;
temp->LChild = NULL;
temp->RChild = start;
start->LChild = temp;
start = temp;
}
else{
printf("Out of memory.");
}
return;
}
//function to insert after a position
void insert_after_pos(){
int data, pos;
NODE temp, q;
printf("\nEnter the position after which data will be inserted: ");
scanf("%d", &pos);
q = start;
for(int i = 0; i < pos-1; i++){
q = q->RChild;
if(q == NULL){
printf("There are less than %d position.", pos);
return;
}
}
temp = (NODE)malloc(sizeof(struct node));
if(temp){
printf("\nEnter the data to be inserted after the %d position: ", pos);
scanf("%d", &data);
temp->info = data;
q->RChild->LChild = temp;
temp->RChild = q->RChild;
temp->LChild = q;
q->RChild = temp;
}
return;
}
//function to delete the node
void delete(){
NODE temp, q;
int num;
printf("\nEnter the data to be deleted: ");
scanf("%d", &num);
if(start->info == num){
temp = start;
start = start->RChild;
start->LChild = NULL;
free(temp);
return;
}
q = start;
while(q->RChild->RChild != NULL){
if(q->RChild->info == num){
temp = q->RChild;
q->RChild = temp->RChild;
temp->RChild->LChild = q;
free(temp);
return;
}
q = q->RChild;
}
if(q->RChild->info == num){
temp = q->RChild;
free(temp);
q->RChild = NULL;
return;
}
printf("\nElement %d is not found on this list.", num);
return;
}
//function to display the list
void display(){
NODE q;
if(start == NULL){
printf("\nList is empty.");
return;
}
q = start;
while(q != NULL){
printf("%d ", q->info);
q = q->RChild;
}
return;
}
//function to reverse the list
void reverse(){
NODE p1, p2;
p1 = start;
p2 = p1->RChild;
p1->RChild = NULL;
p1->LChild = p2;
while(p2 != NULL){
p2->LChild = p2->RChild;
p2->RChild = p1;
p1 = p2;
p2 = p2->LChild;
}
start = p1;
return;
}
int main(){
int choice;
char ch;
start = NULL;
printf("Menu for doubly linked list");
do{
printf("\n1.Insert\n2.Insert at beginning\n3.Insert after position\n4.Display\n5.Delete\n6.Reverse\n7.Exit\nEnter your choice: ");
scanf("%d", &choice);
switch(choice){
case 1: insert();
break;
case 2: insert_at_beg();
break;
case 3: insert_after_pos();
break;
case 4: display();
break;
case 5: delete();
break;
case 6: reverse();
break;
case 7: exit(0);
break;
default: printf("Invalid choice!");
}
printf("\nDo you want to continue ? ");
scanf(" %c", &ch);
}while(ch == 'y' || ch == 'Y');
return 0;
}
在使用gcc cfile.c
编译上述代码时,它正在成功编译。
但它产生运行时错误。在使用gdb
进行调试时,我发现第28行有一些错误。不幸的是我无法理解错误是什么。它正在显示
Program received signal
SIGSEGV, Segmentation fault.
0x000000010040116a in insert () at cfile.c:28
28 start->LChild = temp;
我知道必须使用解除引用指针做一些事情。
但为什么呢?这个代码有什么问题,我在调用start = NULL
函数之前已经完成了insert
。
这是stackdump
Exception: STATUS_ACCESS_VIOLATION at rip=0010040116A
rax=0000000000000000 rbx=00000000FFFFCC40 rcx=0000000600018040
rdx=0000000600028460 rsi=00000006000283B0 rdi=0000000000000000
r8 =00000000FFFFB5FC r9 =000000018013E150 r10=0000000100000000
r11=000000010040111C r12=00000000FFFFCC61 r13=0000000000000000
r14=00000000FFFFCC61 r15=000000018021AE83
rbp=00000000FFFFCBC0 rsp=00000000FFFFCB80
program=E:\Learning\Languages\C\a.exe, pid 8612, thread main
cs=0033 ds=002B es=002B fs=0053 gs=002B ss=002B
Stack trace:
Frame Function Args
000FFFFCBC0 0010040116A (000FFFFCC61, 00000000000, 000FFFFCC61, 000FFFFCCC0)
000FFFFCBF0 001004011E6 (00000000020, FF0700010302FF00, 00180047891, 00000000000)
000FFFFCCC0 00180047902 (00000000000, 00000000000, 00000000000, 00000000000)
00000000000 00180045693 (00000000000, 00000000000, 00000000000, 00000000000)
000FFFFFFF0 00180045744 (00000000000, 00000000000, 00000000000, 00000000000)
End of stack trace
我对stackdump一无所知。所以我无法理解它。
gcc版本:5.4.0 gdb版本:7.10.1
答案 0 :(得分:5)
在这个块中:
if(start == NULL){
temp->LChild = NULL;
start->LChild = temp; // <<< `start` is NULL here !!!
start = temp;
}
你正试图取消引用start
,因为它仍然是NULL
,因此会出现段错误。
答案 1 :(得分:1)
“SIGSEGV,Segmentation fault”类似于无效的指针访问,或者在您的情况下是其他编程语言中已知的简单Null指针异常。
所以你显然无法访问空指针的成员。
答案 2 :(得分:1)
您的代码的问题在于您(在多个地方)使用指针而不确定它不是NULL
。像这样的代码:
NODE start = NULL;
start->LChild = ....whatever....;
当您取消引用NULL
指针时,将导致运行时错误。
因此,在使用指针时,重要的一课是:
在解除引用之前,始终确保指针指向有效的内容
来自@PaulR的回答已经告诉你一个地方你的代码错了,但......还有更多。
在insert()中(如@PaulR已经提到的)
if(start == NULL){
temp->LChild = NULL;
start->LChild = temp; // ups, start is NULL
// You probably just need to delete this line
// as all you want is to make start equal to temp
start = temp;
}
在insert_at_beg()
中 temp->RChild = start;
start->LChild = temp; // ups, start may be NULL
// you need to add a check here like
// if (start != NULL) start->LChild = temp;
start = temp;
在insert_after_pos()
中q = start; // start may be NULL
for(int i = 0; i < pos-1; i++){
q = q->RChild; // so here you may be using a NULL pointer
因此,在进入循环之前,您需要检查start
是否为NULL
,如果是,则返回。
在删除()
中if(start->info == num){ // ups, start may be NULL
// Add a check
反向()
p1 = start; // start may be NULL
p2 = p1->RChild; // ups....
// Add a check
其他一些评论:
1)对于代码的其他读者来说,键入名称NODE
的指针是非常不清楚的。躲开它!或者至少使用一个明确告诉它是指针的名称,例如NODE_P
2)始终检查scanf
返回的值。示例:
if (scanf("%d", &num) != 1)
{
// Input error
....
Add error handling here
....
}