2016-04-06 12 views
0

Ich verstehe, dass ein Fehler auftritt, wenn Sie versuchen, Speicher außerhalb des Bereichs Ihres Programms zuzugreifen, aber ich kann nicht herausfinden, wo meins passiert, oder warum. Ich habe eine Liste definiert: * ListType list = NULL;, und dann füge ich Daten zur Liste hinzu und rufe die Add-Funktion in main auf: addNodeToList (& Liste, Song);Segmentation-Fault in C - Verknüpfte Liste

void addNodeToList(ListType **list, SongType *song) 
{ 
    printf("Starting Add"); 

    NodeType *newNode = malloc(sizeof(NodeType)); 
    NodeType *currNode; 
    currNode = (*list)->head; 
    newNode->data = song; 
    newNode->next = NULL; 

    if(currNode == NULL) { 
     printf("List is Empty"); 
     (*list)->tail = newNode; 
     (*list)->head = newNode; 
    } 
    else { 
     (*list)->tail->next = newNode; 
     (*list)->tail = newNode; 
    } 

} 

Das Lied, das ich vorbei bin richtig initialisiert, und ich kann es Elemente zugreifen, so weiß ich, dass nicht die seg Fehler verursacht. Jede Hilfe wäre sehr willkommen!

typedef struct Song { 
    char title[MAX_STR]; 
    char artist[MAX_STR]; 
    char album[MAX_STR]; 
    char duration[MAX_STR]; 
} SongType; 

typedef struct Node { 
    struct Node *next; 
    SongType *data; 
} NodeType; 

typedef struct List { 
    NodeType *head; 
    NodeType *tail; 
} ListType; 
+1

OK - führen Sie es unter Ihrem Debugger und Schritt durch. –

+0

Auch keine Datendeklarationen/Definitionen gezeigt, und Einrückung ist weniger als optimal :( –

+1

Zumindest sollten Sie die Definitionen von 'ListType' und' SongType' und 'NodeType', aber vorzugsweise ein [MCVE] (http://stackoverflow.com/help/mcve) –

Antwort

1

Es scheint, dass Ihre Berufung Code enthält:

ListType *list = NULL; 

und rufen Sie Ihre Funktion wie folgt aus:

addNodeToList(&list, song); 

und in Ihrer addNodeToList() Funktion Sie haben:

NodeType *currNode; 
currNode = (*list)->head; 

die bedeutet, dass Sie einen Nullzeiger (*list) dereferenzieren, der abstürzt S dein Code. Überprüfen Sie mindestens, ob *list == NULL vor Einstellung currNode, aber Sie müssen den Code überdenken, um den Fall zu behandeln, wo list ein Nullzeiger ist.

Dieser Code wird kompiliert und ausgeführt. Es vermeidet das Problem, indem die Aufteilung der Liste, wenn notwendig:

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

enum { MAX_STR = 64 }; 

typedef struct Song 
{ 
    char title[MAX_STR]; 
    char artist[MAX_STR]; 
    char album[MAX_STR]; 
    char duration[MAX_STR]; 
} SongType; 

typedef struct Node 
{ 
    struct Node *next; 
    SongType *data; 
} NodeType; 

typedef struct List 
{ 
    NodeType *head; 
    NodeType *tail; 
} ListType; 

void addNodeToList(ListType **list, SongType *song); 

void addNodeToList(ListType **list, SongType *song) 
{ 
    printf("Starting Add\n"); 
    assert(list != NULL); 

    if (*list == NULL) 
    { 
     *list = malloc(sizeof(**list)); 
     assert(*list != 0); // Too lazy for production 
     (*list)->head = 0; 
     (*list)->tail = 0; 
     printf("List created\n"); 
    } 
    NodeType *newNode = malloc(sizeof(NodeType)); 
    newNode->data = song; 
    newNode->next = NULL; 
    printf("Node created\n"); 

    NodeType *currNode = (*list)->head; 
    if (currNode == NULL) 
    { 
     printf("List is Empty\n"); 
     (*list)->tail = newNode; 
     (*list)->head = newNode; 
    } 
    else 
    { 
     (*list)->tail->next = newNode; 
     (*list)->tail = newNode; 
    } 
    printf("Node added - all done\n"); 
} 


int main(void) 
{ 
    ListType *list = NULL; 
    SongType data = { "Title", "Artist", "Album", "2m 30s" }; 
    SongType *song = &data; 

    printf("Add song once\n"); 
    addNodeToList(&list, song); 
    printf("Add song again\n"); 
    addNodeToList(&list, song); 
    return 0; 
} 

Beispiel laufen:

Add song once 
Starting Add 
List created 
Node created 
List is Empty 
Node added - all done 
Add song again 
Starting Add 
Node created 
Node added - all done 

Die Code Lecks wie ein Sieb; keine Erinnerung wird freigegeben.

3

in main wenn Sie

ListType* list = NULL; 

dann in Ihrer Funktion sind deklarieren Sie anrufen

(*list)->head 

(*list) dereferencing ist in Ordnung, aber sobald Sie ->head tun es versucht, die ursprüngliche NULL Zuordnung zu dereferenzieren. Sie müssen zuerst Platz für list reservieren.

+0

Er hat seine Hauptfunktion nicht bekannt gegeben. Woher wissen Sie, dass er keinen Platz dafür reserviert? –

+0

Dereferenzierung "Liste" war nicht gut, weil es als 'NULL' weitergegeben wurde. –

+0

Meine Hauptfunktion hat ein paar andere Dinge, die nichts miteinander zu tun haben, aber für die Liste ist das alles, was sie hat. Ich versuchte, es zu ändern, um Speicher unter Verwendung ListType * list = malloc (sizeof (ListType)) zuzuweisen; aber das scheint immer noch nicht den Seg-Fehler zu helfen. – WTL

0

Das Problem befasst sich mit dieser Aussage

ListType *list = NULL; 

Sie nicht addNodeToList für eine Liste aufrufen kann eine solche Art und Weise initialisiert. Ansonsten wird es undefiniertes Verhalten geben.

Sie sollten die Liste die folgende Art und Weise erklären

ListType list = { NULL, NULL }; 

Auch die Funktion addNodeToList kann einfacher

void addNodeToList(ListType *list, SongType *song); 
        ^^^^^^^^^^^^^^ 

deklariert werden Sie können es nennen wie

addNodeToList(&list, song); 

Zum Beispiel

void addNodeToList(ListType *list, SongType *song) 
{ 
    printf("Starting Add"); 

    NodeType *newNode = malloc(sizeof(NodeType)); 

    if (newNode != NULL) 
    { 
     newNode->data = song; 
     newNode->next = NULL; 

     if (list->tail == NULL) 
     { 
      printf("List is Empty\n"); 
      list->head = list->tail = newNode; 
     } 
     else 
     { 
      list->tail->next = newNode; 
      list->tail = newNode; 
     } 
    } 
} 

Oder wenn Sie einen Zeiger auf Liste haben wollen, dann sollten Sie

ListType *list = malloc(sizeof(ListType)); 
list->head = list-tail = NULL;; 

schreiben und dann die Funktion die Definition nennen, von denen ich die folgende Art und Weise zeigte

addNodeToList(list, song); 
+0

Das ist bestenfalls eine Übertreibung ("Sie dürfen' addNodeToList' für eine solche Liste nicht aufrufen "). Sie können es nennen, und es ist legitim, dies zu tun, aber die aufgerufene Funktion muss mit den Dingen anders umgehen als sie es tut. –

+0

@ JonathanLeffler Ich denke, es ist eine gültige Aussage, dass Sie eine Funktion nicht aufrufen dürfen, wenn der Aufruf zu undefiniertem Verhalten führt. :) –