2012-10-24 7 views
2

Tout ce que j'essaie de faire est de libérer un pointeur et il me donne juste l'erreur «adresse invalide»; Bien que l'adresse est clairement valide, comme illustré par les impressions que je mets. Il tente de libérer l'adresse du pointeur, mais échoue toujours. Grâce à valgrind, il donne l'erreur invalide free() en disant que l'adresse est sur la pile du thread 1? Le code ci-dessous est exécutable; quelqu'un peut-il aider?adresse de pointeur invalide lors de la tentative de libérer

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <stdint.h> 

#define SUCC 1 
#define FAIL -1 

typedef struct bucket { 
    char *key; 
    void *value; 
    struct bucket *next; 
} Bucket; 

typedef struct { 
    int key_count; 
    int table_size; 
    void (*free_value)(void *); 
    Bucket **buckets; 
} Table; 


extern unsigned int hash_code(const char *key) { 
    unsigned int hash = 0, i = 0; 
    while(i < strlen(key)) { 
     hash ^= ((hash << 3) | (hash >> 29)) + key[i++]; 
    } 
    return hash; 
} 

/*Makes copy of string and returns pointer to it*/ 
char * cpy(const char *str) { 
    char *new = malloc(sizeof(char *)); 
    if(new) 
     strcpy(new, str); 
    return new; 
} 


int create_table(Table ** table, int table_size, void (*free_value)(void *)) { 
    *table = malloc(sizeof(Table)); 
    if(table && table_size != 0) { 
     int i = 0; 
     (*table)->key_count = 0; 
     (*table)->table_size = table_size; 
     (*table)->free_value = free_value; 
     (*table)->buckets = calloc(table_size, sizeof(Bucket *)); 
     while(i < table_size) 
      (*table)->buckets[i++] = NULL; 
     return SUCC; 
    } 
    return FAIL; 
} 


int put(Table * table, const char *key, void *value) { 
    if(table && key) { 
     int hash = hash_code(key)%table->table_size; 
     Bucket *curr = table->buckets[hash]; 
     while(curr) { 
      if(strcmp(curr->key, key) == 0) { 
       if(table->free_value) 
        table->free_value(curr->value); 
       printf("addr of ptr: %p\n", value); 
       curr->value = value; 
       printf("addr of curr ptr: %p\n", curr->value); 
       return SUCC; 
      } 
      curr = curr->next; 
     } 
     curr = malloc(sizeof(Bucket)); 
     curr->key = cpy(key); 
     printf("addr of ptr: %p\n", value); 
     curr->value = value; 
     printf("addr of curr ptr: %p\n", curr->value); 
     curr->next = table->buckets[hash]; 
     table->buckets[hash] = curr; 
     table->key_count++; 

     return SUCC; 
    } 
    return FAIL; 
} 


int remove_entry(Table * table, const char *key) { 
    if(table && key) { 
     int hash = hash_code(key)%(table->table_size); 
     Bucket *curr = table->buckets[hash], *prev = table->buckets[hash]; 
     while(curr) { 
      printf("attempt"); 
      if(strcmp(curr->key, key) == 0) { 
       void * test = curr->value; 
       printf("at addr %p\n", test); 
       table->free_value(test); 
       printf("freed"); 

       if(table->free_value){ 
        table->free_value(curr->value); 
       } 
       free(curr->key); 
       curr->key = NULL; 
       curr->value = NULL; 
       table->key_count--; 
       if(prev == curr) 
        table->buckets[hash] = curr->next; 
       else 
        prev->next = curr->next; 
       free(curr); 
       curr = NULL; 
       return SUCC; 
      } 
      prev = curr; 
      curr = curr->next; 
     } 
    } 
    return FAIL; 
} 

Et le fichier de test qui montre l'erreur:

#include <stdio.h> 
#include <stdlib.h> 
#include "htable.h" 


int main() { 
    Table *t; 
    int num2 = 3; 
    printf("create: %d\n",create_table(&t, 2, free)); 
    printf("addr of ptr: %p\n",(void *)&num2); 
    printf("put %s: %d\n","test",put(t, "test", &num2)); 
    printf("rem key: %d\n",remove_entry(t, "test")); 
    return 0; 
} 

Répondre

3

Vous essayez de free() une variable de la pile: num2 (en main()):

int num2 = 3; 

Plus tard, vous avez cet appel:

printf("put %s: %d\n","test",put(t, "test", &num2)); 

Vous transmettre l'adresse de num2 à put() , ce qui signifie que remove_entry() va essayer de le libérer plus tard. C'est illégal. Vous ne pouvez pas libérer une variable allouée sur la pile. Vous devez allouer dynamiquement num2 à la place:

int* num2 = malloc(sizeof(int)); 
*num2 = 3; 

Il y a un autre problème aussi bien que. Dans ce code:

void * test = curr->value; 
printf("at addr %p\n", test); 
table->free_value(test); 
printf("freed"); 

if(table->free_value){ 
    table->free_value(curr->value); 
} 

Vous libérez deux fois curr->value, parce que vous êtes libérant test qui est juste une copie du pointeur.

+0

Eh bien cela a corrigé ce problème, mais il y a encore quelque chose d'autre qui ne va pas avec le code parce que maintenant je reçois de la mémoire avant le bloc alloué sur une instruction free() ... merci pour l'aide. – user1769889

+0

@ user1769889 Trouvé un autre problème. J'ai mis à jour la réponse. –

+0

Ouais, j'allais dire que votre solution ne fonctionnait pas quand je l'ai essayé pour la première fois, mais j'ai réalisé que je n'avais pas sorti cette ligne de test. Merci – user1769889

5

Ceci est cassé:

char *new = malloc(sizeof(char *)); 

La quantité de mémoire dont vous avez besoin est basé sur ce que vous devez stocker, qui est la chaîne. Vous voulez:

char *new = malloc(strlen(str) + 1); 

Ou, mieux encore, il suffit d'utiliser strdup.

+0

Non, toujours la même erreur. De plus, je reçois l'erreur sur la valeur, pas la clé. Mais fait le changement néanmoins, merci. – user1769889

Questions connexes