2015-10-11 6 views
1

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

У меня есть LinkedList структуру, которая выглядит следующим образом:

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 

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

В строке, я с пометкой "< - эта строка ", когда я проверяю параметр имени (db) databases_list.head-> данных, я вижу« \ 222 \ 017 »вместо« mydb », как я ожидал (например, когда я проверяю имя db1->). Что я делаю не так?

+0

Добро пожаловать в Переполнение стека. Вскоре прочитайте страницу [О программе]. Мы предпочитаем видеть компилируемый код - и показанный заголовок не будет компилироваться, потому что у вас есть элементы 'listNode *' в вашей структуре 'linkedList', прежде чем вы сказали, что такое' listNode'. Пожалуйста, покажите реальный код, если он компилируется, и если он не компилируется, вы должны спрашивать о ошибках компиляции, а не о ошибках времени выполнения, которые вам кажутся. –

+0

Обратите внимание, что вы наступаете на тонкий лед с именем тега 'struct_listNode'. Имена, начинающиеся с подчеркивания, в основном зарезервированы для реализации. Полные детали немного более нюансированы, чем это, но это не грубое завышение и гораздо проще заявить, чем нюансные правила.В большинстве случаев вам удастся использовать такие имена, но нет никаких гарантий, что вы всегда это сделаете. Протектор осторожно. –

+0

Код отладки - это ценный навык, который вы должны изучить, если собираетесь продолжить программирование. Я не говорю, что вы не инвестировали усилий в выяснение, что не так с вашим кодом. Но stackoverflow не предназначен как инструмент отладки (хотя это отличный ресурс для использования при отладке). Если у вас есть конкретный вопрос о том, почему какой-то конкретный фрагмент кода работает не так, как ожидалось, тогда это будет более подходящий вопрос. Я рекомендую изолировать линию (линии) или, по крайней мере, функцию (ы), в которой все начинает идти наперекосяк. Я гарантирую, что вы лучше поймете свой код после этого. – fvgs

ответ

0

Я принял измененный код и немного отредактировал некоторые из моих предрассудков, поэтому мои номера строк, вероятно, немного отличаются от ваших. Когда я бегу под 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, и я не доверяю файлу подавления, чтобы дать мне полезную информацию. Он был построен под Йосемити, и я также получаю «неизвестные fcntl звонки», отслеживаемые valgrind.

+0

Спасибо! похоже, что ты прав. Честно говоря, я не уверен, почему это должно быть указателем на указатель ... он и структуры db и table были частью шаблона, указанного в классе, который я принимаю. – angelok

0

Я думаю, что строка внутри вашего тестового кода здесь может быть испорчена.

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

когда вы делаете SizeOf (дБ *) вы фактически получаете размер указателя НЕ дб STRUCT. Вы действительно должны делать sizeof (db). Поскольку размер элемента устанавливается только на размер указателя, вы не копируете достаточное количество данных, и когда вы читаете назад, вы читаете поврежденные данные из памяти, вызывая неправильные значения.

+0

Спасибо за ваши мысли. Я пробовал в обоих направлениях, и он, похоже, не ведет себя иначе. – angelok