2016-07-07 56 views
2

我試圖在C中實現一個鏈表作爲練習。我已在結構定義爲這樣:訪問結構成員時valgrind的讀/寫錯誤無效

typedef struct node { 
    int data; 
    struct node* next; 
} 
node; 

typedef struct list { 
    size_t size; 
    node* head; 
} 
list; 

現在,Valgrind的抱怨的功能是這些:

創建()

list* create() { 
    // alocate memory for a new list 
    list* list = malloc(sizeof(list)); 

    if (list != NULL) { 
     list->head = NULL; // this is line 65 
     list->size = 0; 
    } 

    // return pointer to the allocated memory 
    return list; 
} 

插入()

void insert(int data, list* list) { 
    if (list == NULL) 
     return; 

    // allocate memory for new node 
    node* newNode = malloc(sizeof(node)); 

    // check if allocation was successful 
    if (newNode == NULL) 
     return; 

    // initialize new node's data 
    newNode->data = data; 

    // make newNode the head of the list 
    newNode->next = list->head; // this is line 88 
    list->head = newNode; 

    // increment size 
    (list->size)++; 
} 

destroy()方法

void destroy(list* list) { 
    if (list == NULL) 
     return; 

    node* current = list->head; // this is line 154 
    while (current != NULL) { 
     node* temp = current; 
     current = current->next; 
     free(temp); 
    } 

    free(list); 
} 

主要的()如下:

int main(void) { 
    list* list = create(); 
    insert(1, list); 
    destroy(list); 
    return 0; 
} 

而這正是Valgrind的輸出:

==10601== 1 errors in context 1 of 4: 
==10601== Invalid read of size 8 
==10601== at 0x400A33: destroy (slist.c:154) 
==10601== by 0x400AAE: main (slist.c:167) 
==10601== Address 0x51fc048 is 0 bytes after a block of size 8 alloc'd 
==10601== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==10601== by 0x4007C3: create (slist.c:62) 
==10601== by 0x400A93: main (slist.c:165) 
==10601== 
==10601== 
==10601== 1 errors in context 2 of 4: 
==10601== Invalid write of size 8 
==10601== at 0x400866: insert (slist.c:89) 
==10601== by 0x400AA5: main (slist.c:166) 
==10601== Address 0x51fc048 is 0 bytes after a block of size 8 alloc'd 
==10601== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==10601== by 0x4007C3: create (slist.c:62) 
==10601== by 0x400A93: main (slist.c:165) 
==10601== 
==10601== 
==10601== 1 errors in context 3 of 4: 
==10601== Invalid read of size 8 
==10601== at 0x400852: insert (slist.c:88) 
==10601== by 0x400AA5: main (slist.c:166) 
==10601== Address 0x51fc048 is 0 bytes after a block of size 8 alloc'd 
==10601== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==10601== by 0x4007C3: create (slist.c:62) 
==10601== by 0x400A93: main (slist.c:165) 
==10601== 
==10601== 
==10601== 1 errors in context 4 of 4: 
==10601== Invalid write of size 8 
==10601== at 0x4007DA: create (slist.c:65) 
==10601== by 0x400A93: main (slist.c:165) 
==10601== Address 0x51fc048 is 0 bytes after a block of size 8 alloc'd 
==10601== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==10601== by 0x4007C3: create (slist.c:62) 
==10601== by 0x400A93: main (slist.c:165) 
==10601== 
==10601== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0) 

如果我理解正確的輸出時,問題似乎是訪問struct list成員變量。但是,我不明白爲什麼訪問這些變量是一個問題。 malloc(sizeof(list))應該爲兩個成員分配足夠的內存,那麼問題出在哪裏?

回答

5
list* list = malloc(sizeof(list)); 

哎呀! sizeof中的list是您聲明的指針,而不是類型。所以你只有malloc - 足夠的內存爲一個指針,而不是你想要的結構。

避免使用變量名稱對類型名稱進行遮蔽。或者,如果你必須使用

list* list = malloc(sizeof(struct list)); 
+0

良好的漁獲物。我知道的命名將某處打... –

5

的問題是在這裏:

list* list = malloc(sizeof(list)); 

您有list一個typedef和一個名爲list變量。 sizeof運算符取得變量的大小,而不是類型。

作爲一項規則,不命名變量同名類型:

list* create() { 
    // alocate memory for a new list 
    list* mylist = malloc(sizeof(list)); 

    if (mylist != NULL) { 
     mylist ->head = NULL; 
     mylist ->size = 0; 
    } 

    // return pointer to the allocated memory 
    return mylist ; 
} 
2

通過@aschepler@dbush

提供不同的解決方案的問題是明確確定:當使用sizeof(),使用解除引用的變量的大小而不是該類型的大小。

// some_type *ptr = malloc(sizeof (some_type)); 
some_type *ptr = malloc(sizeof *ptr); 

即使在陰影類型list和可變list,這個工程

list* create() { 

    list* list; 

    printf("%zu\n", sizeof(list)); // compiles but the needed code 
    printf("%zu\n", sizeof list); // compiles but the needed code 
    printf("%zu\n", sizeof *list); // good 

    // allocate memory for a new list 
    list = malloc(sizeof *list); 
    ... 

打印

4 
4 
8