2017-02-28 125 views
0

嘗試使用Fedora gcc下面的代碼爲簡單鏈接列表添加新節點到列表尾部。編譯沒有錯誤。在執行期間,它顯示分段錯誤,核心轉儲。 在MS Windows上,它正在工作。鏈接列表錯誤「分段錯誤」核心轉儲

#include<stdio.h> 
#include<stdlib.h> 

struct Node 
{ 
    int data; 
    struct Node *next; 
}; 

void insertion(struct Node *); 
void display(struct Node *); 

int main(void) 
{ 
    struct Node *head; 
    head=NULL; 
    head->next=NULL; 

    int choice, cont; 

    do 
    { 
     printf("1.Insert  2.Display  3.Exit"); 
     scanf("%d",&choice); 

     if(choice==1) 
     { 
      insertion(head); 
     } 
     else if(choice==2) 
     { 
      display(head); 
     } 
     else if(choice==3) 
     { 
      exit(0); 
     } 
     else 
     { 
      printf("Wrong choice"); 
     } 
     printf("Continue? Press 1 otherwise 0:"); 
     scanf("%d",&cont); 
    }while(cont==1); 

    return 0; 
} 

void insertion(struct Node *start) 
{ 
    int data; 
    struct Node *temp=NULL; 
    temp->next=NULL; 
    struct Node *mnew=NULL; 
    mnew->next=NULL; 

    mnew=(struct Node *)malloc(sizeof(struct Node)); 

    printf("Enter data:"); 
    scanf("%d",&data); 

    mnew->data=data; 

    if(start==NULL) 
    { 
     start=mnew; 
    } 
    else if(start!=NULL && start->next==NULL) 
    { 
     start->next=mnew; 
    } 
    else 
    { 
     temp=start; 
     while(temp->next!=NULL) 
     { 
      temp=temp->next; 
     } 
     temp->next=mnew; 
    } 
} 

void display(struct Node *start) 
{ 
    struct Node *temp=NULL; 
    temp->next=NULL;  
    if(start==NULL) 
    { 
     printf("\nNothing to display!"); 
    } 
    else if(start!=NULL && start->next==NULL) 
    { 
     printf("%d",start->data); 
    } 
    else 
    { 
     temp=start; 
     while(temp!=NULL) 
     { 
      printf("%d",temp->data); 
      temp=temp->next; 
     } 
    } 
} 

您的幫助表示讚賞。

+1

時間來學習如何使用調試器。 –

+0

此外'start = mnew;'不會改變'head'的主要值.....你應該研究一些關於指針的東西。 – LPs

回答

2

仔細看看例如從insertion函數以下兩行:

struct Node *temp=NULL; 
temp->next=NULL; 

第一個定義一個指針struct Node並使其爲空指針。下一行你解引用這個空指針,這是無效的,並導致未定義的行爲

你在多個地方都有同樣的問題,兩者完全一樣,並且一般也取消引用空指針。

+0

...或OP可以使用'calloc'而不是'malloc' – LPs

+0

此外'start = mnew;'不會改變'head'主值 – LPs

+0

@LPs - 如果你建議'calloc'作爲設置所有指針的快捷方式在結構爲NULL時,知道零位模式不能保證是NULL指針的值。 [參見'calloc'標準註釋](http://port70.net/~nsz/c/c11/n1570.html#note296)以供參考。 – StoryTeller

5
head=NULL; 
head->next=NULL; 

這段代碼永遠無法工作,就好像它是指向NULL(又名無處)您無法訪問或賦值的head屬性。

+0

我已經評論了第二行,現在正在執行。但插入3個節點後,顯示功能報告「無顯示!」這意味着開始仍然是NULL。 –

+0

這是因爲你沒有更新'head' - 你必須把它作爲參考傳入你的插入函數,或者讓這個函數返回新的開始,這樣你就可以把它分配給'head' –

+0

此外'start = mnew; '不改變'head'的主值 – LPs

1

您不能使用空指針訪問數據。因此,此代碼片段(以及類似的代碼片段)

struct Node *head; 
head=NULL; 
head->next=NULL; 
^^^^^^^^^^^^^^^ 

無效。

至於函數insertion那麼你必須通過引用傳遞頭部。否則,該功能將處理頭部的副本,並且功能中頭部副本的任何更改都不會影響原始頭部。

此外,如果內存分配將失敗,則希望函數能夠發出相關信號。因此,代替退貨類型void,最好使用退貨類型int

那麼函數的聲明可以像

int insertion(struct Node **); 
^^^   ^^^^^^^^^^^^^^ 

功能可以像

int insertion(struct Node **start) 
{ 
    int data; 

    printf("Enter data: "); 
    scanf("%d", &data); 

    struct Node *temp = (struct Node *)malloc(sizeof(struct Node)); 

    int success = temp != NULL; 

    if (success) 
    { 
     temp->data = data; 
     temp->next = NULL; 

     while (*start) start = &(*start)->next; 

     *start = temp; 
    } 

    return success; 
} 

的功能來定義可以被稱爲以下方式

insertion(&head); 

功能display能看起來像

void display(struct Node *start) 
{ 
    if (start == NULL) 
    { 
     printf("\nNothing to display!\n"); 
    } 
    else 
    { 
     for (; start; start = start->next) 
     { 
      printf("%d ", start->data); 
     } 
     putchar('\n'); 
    } 
} 
+0

我很驚訝爲什麼這甚至可以在Windows上工作?任何體面的編譯器都應該能夠捕捉到這個並提出警告。 –

0

如前面的註釋,指向指向另一個NULLNULL指針未定義(導致指針應該保存地址)。 現在一些建議:

1)定義的結構如下所示:

typedef struct Node *node_pointer; 

這將使它更容易定義指針爲結構。

2)

mnew=malloc(sizeof(*mnew)); //this is easier, and this should be before the ..->next=NULL; 

還檢查是否分配成功:

if (!mnew) 
    return; //return something needed