2017-01-25 2 views
0

이중 연결 목록 용 C 프로그램을 작성 중입니다. 다음 코드는 main 기능과 insert 기능을 포함합니다.이 프로그램이 런타임 오류를 발생시키는 이유는 무엇입니까?

성공적으로 컴파일 gcc cfile.c로 위의 코드를 컴파일에 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; 
} 

. 그러나 런타임 오류가 발생합니다. gdb으로 디버깅 할 때 28 행에 오류가 있음을 알게되었습니다. 불행히도 오류가 무엇인지 이해할 수 없습니다. 보이는 중임

역 참조 포인터로 무엇인가를해야한다는 것을 알고 있습니다.

하지만 왜? 이 코드가 잘못된 것은 무엇입니까? insert 함수를 호출하기 전에 start = NULL을 완료했습니다.

는 여기가 STACKDUMP에 대해 아무것도 모르는 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 

입니다. 그래서 나는 그것을 이해할 수 없다.

GCC 버전 : 5.4.0 GDB 버전 : 7.10.1

답변

5

이 블록에서 : 여전히 NULL 동안

if(start == NULL){ 
    temp->LChild = NULL; 
    start->LChild = temp; // <<< `start` is NULL here !!! 
    start = temp; 
} 

당신이 따라서, 역 참조 start하려고하는 세그 폴트.

+0

어떤 수정이 필요합니까? – user123456987

+1

이 시점에서 코드를 사용하여 달성하고자하는 목표에 달려 있습니다. 아무도 사용자의 의도를 실제로 추측 할 수는 없지만 사용자가 노드를 삽입하려고 시도하고 논리가 혼란스러워하는 것 같습니다. . –

+0

예 목록에 노드를 삽입하려고합니다. – user123456987

1

"SIGSEGV, Segmentation fault"는 잘못된 포인터 액세스 또는 다른 프로그래밍 언어에서 알려진 간단한 Null 포인터 예외와 같은 것입니다.

따라서 널 포인터 멤버에 분명히 액세스 할 수 없습니다.

1

코드에있는 문제는 (여러 곳에서) NULL이 아닌지 확인하지 않고 포인터를 사용한다는 것입니다. 이 같은 코드 : 당신이 NULL 포인터를 역 참조 될 때

NODE start = NULL; 
start->LChild = ....whatever....; 

는 런타임 오류가 발생합니다. 포인터로 작업 할 때

그래서 중요한 교훈은 다음과 같습니다

항상

하는 역 참조하기 전에 포인터가 유효한 뭔가를 가리키고 있는지 확인이

@PaulR에서 그 대답은 이미 당신이 한 장소를 알려줍니다 코드가 잘못되었지만 더 많은 것이 있습니다.

인서트 ( 에서

) insert_at_beg에서

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; 
} 

() (@PaulR 이미 언급 됨) 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 
에서

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; 

루프에 들어가기 전에 startNULL인지 확인해야합니다. 삭제에서

() 역에서

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) 이름에 대한 포인터를 typedef'ing NODE입니다 다른 독자의 코드에 대해서는 매우 불분명합니다. 그것을 피하십시오! 또는 적어도 그것이 포인터라는 것을 분명하게 알려주는 이름을 사용하십시오. NODE_P

2) 항상 scanf에 의해 반환 된 값을 확인하십시오. 예 :

if (scanf("%d", &num) != 1) 
{ 
    // Input error 
    .... 
    Add error handling here 
    .... 
} 
관련 문제