2014-12-21 11 views
5

Sto cercando di implementare un dizionario di parole usando una tabella di hash, quindi ho bisogno di avere globale, e in uno dei miei file di intestazione ho dichiararlovalore non inizializzato è stato creato da uno stanziamento mucchio

extern node** dictionary; 

Dove nodo è

typedef struct node 
{ 
    char* word; 
    struct node* next; 
} node; 

Poi in un altro file in cui funzioni sono definite includo l'intestazione che ha la dichiarazione di dizionario, e anche io aggiungere in cima

node** dictionary; 

Poi nella funzione che carica in realtà il dizionario in primo luogo ho allocare memoria per le liste collegate che renderanno la tabella hash

bool load(const char* dict_file) 
{ 
    dictionary = malloc(sizeof(node*) * LISTS); 

    FILE* dict = fopen(dict_file, "r"); 

    if(dict == NULL) 
     return false; 

    char buffer[MAX_LEN + 2]; 

    size_dict = 0; 

    while(fgets(buffer, MAX_LEN + 2, dict) != NULL) 
    { 
     node* new_node = malloc(sizeof(node)); 

     int len = strlen(buffer); 

     new_node->word = malloc(sizeof(char) * (len)); 

     //avoid \n 
     for(int i = 0; i < len - 1; i++) 
      new_node->word[i] = buffer[i]; 

     new_node->word[len - 1] = '\0'; 

     new_node->next = NULL; 

     int index = hash(buffer); 

     new_node->next = dictionary[index]; 

     dictionary[index] = new_node; 

     size_dict++; 
    } 

    if (ferror(dict)) 
    { 
     fclose(dict); 
     return false; 
    } 

    fclose(dict); 
    return true; 
} 

Così il programma funziona bene, ho poi libera tutta la memoria allocata per archi e nodi e quando eseguo valgrind (un debugger che rileva perdite di memoria) dice che non sono possibili perdite di memoria, ma dice che c'è un errore Il valore non inizializzato è stato creato da un'allocazione dell'heap e mi reindirizza alla riga esatta in cui sono allocare memoria per dictionary la prima riga esatta della funzione di caricamento che ho scritto sopra.
Cosa sto sbagliando? Immagino che il modo in cui uso globalmente lo dictionary sia sbagliato, quindi qualcuno può suggerire un altro modo per mantenerlo globale ed evitare questo errore?

+2

Il codice che hai mostrato non riproduce l'errore, quindi è probabilmente a causa di qualcos'altro che non ci hai mostrato. – Rufflewind

+0

Ma l'ho fatto solo perché mi invia solo a questa linea, il seguente codice è solo un file che legge, parola per parola, creazione di un nodo per ogni parola e selezione di ciascun nodo nella lista collegata appropriata (26 di essi , dove il nodo va dipende dalla prima lettera della parola che rappresenta) –

+2

Il problema è nel resto del codice, un motivo particolare per cui non lo si pubblica? Sto cercando di aiutarti, ma è richiesto il resto del codice. –

risposta

7

Nel codice aggiornato si utilizza un puntatore non inizializzato:

dictionary = malloc(sizeof(node*) * LISTS); 

// .... code that does not change dictionary[i] for any i 

new_node->next = dictionary[index]; // use uninitialized pointer 

Dato che le persone avevano già intuito, questo funziona solo se si era pre-impostare tutti i puntatori di essere NULL prima di entrare in questo ciclo:

dictionary = malloc(sizeof(node*) * LISTS); 
if (!dictionary) 
    return false; 

for (size_t i = 0; i < LISTS; ++i) 
    dictionary[i] = NULL; 
+0

NB. La tua riga 'new_node-> next = NULL;' è ridondante per poi sovrascriverla subito dopo. –

+0

sì, lo so, avrebbe dovuto essere per ogni nodo * nel dizionario, invece, altrimenti l'ultimo nodo punta a qualche valore di spazzatura intatto di essere NULL, grazie. –

3

L'allocazione heap assegnata a dictionary utilizza malloc che non inizializza i byte restituiti. Quindi dictionary nel codice che hai postato finisce per essere una matrice di puntatori non inizializzati. Presumibilmente, continuerai a usare quei puntatori in un modo che valgrind sa essere un errore.

Un modo semplice per risolvere questo problema è utilizzare calloc anziché malloc, perché azzera i byte restituiti. In alternativa, utilizzare memset per azzerare i byte.

+0

Dove ho scritto // codice ...Nella funzione di caricamento ho effettivamente saltato 60 righe di codice, dove carico parola per parola da un file, creo un nuovo nodo per ogni parola e creo il nodo * a cui punta dictionary, un puntatore a tali nodi e tutti gli altri il nodo * per il quale ho assegnato memoria è effettivamente utilizzato –

+0

Effettivamente il mio programma funziona correttamente, le parole rapresentanti dai nodi sono correttamente distribuite nell'array di node * e quindi liberate –

+1

L'uso di 'calloc' nasconde il fatto che non si inizializza qualcosa da qualche parte, a meno che tu non voglia inizializzare esplicitamente a '0' usando' calloc', si nasconde un altro problema. –