2016-04-06 4 views
0

Я понимаю, что ошибка набора происходит, когда вы пытаетесь получить доступ к памяти из объема вашей программы, но я не могу понять, где мое происходит, или почему. У меня есть определенный список: * ListType list = NULL;, , а затем я добавляю данные в список, вызывающий функцию добавления в главном: addNodeToList (& list, song);Сегментация-ошибка в C - Связанный список

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

} 

песня Я передаю правильно инициализирована, и я могу получить доступ к его элементам, так что я знаю, что не вызывает ошибку сегм. Любая помощь будет очень оценена!

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 - запустить его под вашим отладчиком и шаг за шагом. –

+0

Кроме того, никакие декларации/определения данных не показаны, а отступ меньше, чем оптимальный :( –

+1

По крайней мере, вы должны опубликовать определения «ListType» и «SongType» и «NodeType», но предпочтительно [MCVE] (http://stackoverflow.com/help/mcve) –

ответ

1

Оказывается, что ваш код вызова содержит:

ListType *list = NULL; 

и вы называете функцию следующим образом:

addNodeToList(&list, song); 

и в вашей addNodeToList() функции у вас есть:

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

который означает, что вы разыскиваете нулевой указатель (*list), который краше s ваш код. Как минимум, проверьте, *list == NULL перед установкой currNode, но вам нужно переосмыслить код, чтобы обработать случай, когда list является нулевым указателем.

Этот код компилируется и запускается. Это позволяет избежать проблемы путем выделения списка, когда необходимо:

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

Пример запуска:

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 

Кодовые утечки, как решето; память не освобождается.

3

в main если вы объявляя

ListType* list = NULL; 

то в вашей функции вы звоните

(*list)->head 

разыменования (*list) это хорошо, но как только вы ->head он пытается для разыменования исходного задания NULL. Сначала вам нужно выделить некоторое пространство для list.

+0

Он не разместил свою основную функцию. Как вы знаете, что он не выделяет для этого места? –

+0

Выделение 'list' было неудобно, потому что оно было передано как' NULL'. –

+0

Моя основная функция имеет некоторые другие, совершенно несвязанные вещи в ней, но для списка это все, что у него есть. Я попытался изменить его, чтобы выделить память, используя ListType * list = malloc (sizeof (ListType)); но это, по-видимому, не помогает разлому seg. – WTL

0

Проблема имеет дело с этим утверждением

ListType *list = NULL; 

Вы не можете назвать addNodeToList для списка инициализации такого пути. В противном случае будет неопределенное поведение.

Вы должны объявить список следующим образом

ListType list = { NULL, NULL }; 

Также функция addNodeToList может быть объявлена ​​проще

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

Вы можете назвать это как

addNodeToList(&list, song); 

Например

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

Или, если вы хотите иметь указатель на список, то вы должны написать

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

, а затем вызвать функцию определения которой я показал следующий способ

addNodeToList(list, song); 
+0

Это преувеличение в лучшем случае («Вы не можете называть' addNodeToList' для такого списка »). Вы можете назвать это, и это законно, но вызываемая функция должна обрабатывать вещи по-другому, чем она делает. –

+0

@JonathanLeffler Я думаю, что это допустимое утверждение, что вы не можете вызывать функцию, если вызов приводит к неопределенному поведению. :) –

Смежные вопросы