在C中使用void指针模拟泛型链表



我是C的新手,我认为这里可能有一个指针的问题。任何帮助将不胜感激!

我有一个像这样的链表结构体:

ll.h:

#ifndef LLTEST_LL_H
#define LLTEST_LL_H
#include <stdlib.h>
typedef struct _listNode {
    void *data;
    struct _listNode *next;
} listNode;
typedef struct {
    int logicalLength;
    int elementSize;
    listNode *head;
    listNode *tail;
} linkedlist;
typedef struct table {
    const char* name;
    size_t col_count;
    size_t length;
} table;
typedef struct db {
    const char* name;
    size_t table_count;
    table** tables;
} db;
void list_append(linkedlist *list, void *element);
void create_list(linkedlist *list, int elementSize);
void create_db(const char* db_name, db** db);
#endif //LLTEST_LL_H

c

#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include "ll.h"
linkedlist databases_list;
void create_list(linkedlist *list, int elementSize)
{
    list->logicalLength = 0;
    list->elementSize = elementSize;
    list->head = NULL;
    list->tail = NULL;
}
void list_append(linkedlist *list, void *element)
{
    listNode *node = malloc(sizeof(listNode));
    node->data = malloc(list->elementSize);
    node->next = NULL;
    memcpy(node->data, element, list->elementSize);
    if(list->logicalLength == 0) {
        list->head = list->tail = node;
    } else {
        list->tail->next = node;
        list->tail = node;
    }
    list->logicalLength++;
}
listNode* find_database_node(char *name){
    listNode *node = databases_list.head;
    //bool result = true;
    listNode *found_node = NULL;
    while(node != NULL) {
        db *item = (db *)node->data;
        if (strcmp(item->name, name) == 0){
            found_node = node;
            break;
        }
        node = node->next;
    }
    return found_node;
}
void get_db_pool(char *name, db *value){
    listNode *node = find_database_node(name);
    if(node != NULL){
        value = (db *)node->data;
    }
    else{
        value = NULL;
    }
}
void set_db_pool(db* value){
    list_append(&databases_list, (void *)value);
}
void create_db(const char* db_name, db** db) {
    if (*db == NULL) {
        *db = malloc(sizeof(db));
    }
    (*db)->name = db_name;
    (*db)->table_count = 0;
    (*db)->tables = NULL;
}
int main() {
    create_list(&databases_list, sizeof(db *));
    char* db_name= "mydb";
    db* db1 = NULL;
    create_db(db_name, &db1);
    set_db_pool(db1); //<--this line
    return 0;
}

在我标记了"<——this line"的行上,当我检查(db)databases_list时。在head->data的name参数中,我看到的是"22217",而不是我所期望的"mydb"(例如当我检查db1->name时)。我做错了什么?

我对修改后的代码进行了一些编辑,以适应我的一些偏见,因此我的行号可能与您的行号略有不同。当我在valgrind下运行它时,我得到一个抱怨:

==55831== Invalid write of size 8
==55831==    at 0x100000EC7: main (ll17.c:78)
==55831==  Address 0x100a7c350 is 8 bytes after a block of size 8 alloc'd
==55831==    at 0x1000066F1: malloc (vg_replace_malloc.c:303)
==55831==    by 0x100000EB9: main (ll17.c:73)
==55831== 
==55831== Invalid write of size 8
==55831==    at 0x100000ECF: main (ll17.c:78)
==55831==  Address 0x100a7c348 is 0 bytes after a block of size 8 alloc'd
==55831==    at 0x1000066F1: malloc (vg_replace_malloc.c:303)
==55831==    by 0x100000EB9: main (ll17.c:73)

第73行如下所示:

void create_db(const char* db_name, db** db) {
    if (*db == NULL) {
        *db = malloc(sizeof(db));  // 73
    }

这为指针(严格地说,指针指向指针)分配了足够的空间,而不是为db结构分配空间。

  • 你应该避免使用与其(基)类型同名的变量-这会混淆除了编译器之外的所有人。

你真的需要:

void create_db(const char* db_name, db** db) {
    if (*db == NULL) {
        *db = malloc(sizeof(**db));
    }

有了这个更改,代码在valgrind下运行正常。根据我的valgrind版本,它泄漏了很多,但我最近从Mac OS X 10.10 Yosemite升级到10.11 El Capitan,我不相信我的抑制文件能给我任何有用的信息。它是在约塞米蒂公园下建造的,我还收到了valgrind跟踪的"未知fcntl呼叫"。

我认为你的测试代码中这一行可能有缺陷。

create_list(&databases_list, sizeof(db *), NULL);

当你做sizeof(db *)时,你实际上得到的是指针的大小,而不是db结构体。你应该用sizeof(db)由于元素的大小只被设置为指针的大小,所以你没有复制足够的数据,当你回读时,你从内存中读取损坏的数据,导致你的值不正确。

相关内容

  • 没有找到相关文章

最新更新