2016-07-07 54 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