2012-12-14 6 views
0

tableau (C) realloc modifie les données ont souligné par des élémentstableau (C) realloc modifie _pointed_ de données par des éléments

Bonjour,

Un joli bug bizarre je me sens comme le partage ;-) Nécessite quelques explications préliminaires :

D'abord, j'ai un type de chaînes PString qui conservent leur taille (et une valeur de hachage), suivi par un membre de tableau flexible avec les octets. Voici le type et le type de constructeur (la déclaration printfl à la fin est debug):

typedef struct { 
    size_t size; 
    uint  hash; 
    char  bytes[]; 
} PString; 

// offset from start of pstring struct to start of data bytes: 
static const size_t PSTRING_OFFSET = sizeof(size_t) + sizeof(uint); 

PString * pstring_struct (string str, size_t size, uint hash) { 
    // memory zone 
    char *mem = malloc(PSTRING_OFFSET + size * sizeof(char)); 
    check_mem(mem); 

    // string data bytes: 
    memcpy(mem + PSTRING_OFFSET, str, size); 
    mem[PSTRING_OFFSET + size] = NUL; 

    // pstring struct: 
    PString * pstr = (PString *) mem; 
    pstr->size = size; 
    pstr->hash = hash; 

    printfl("*** str:'%s' (%u) --> pstr:'%s' (%u) 0x%X", 
    str, size, pstr->bytes, pstr->size, pstr); /////////////////////// 
    return pstr; 
} 

[Tout commentaire sur cet accueil de la construction: Je ne sais pas du tout faire les choses, ici. Il est la première fois que j'utilise les membres du groupe flexibles, et je ne pouvais pas trouver exemples de les utiliser dans alloués struct.]

En second lieu, ces pstrings sont stockés dans un pool de chaîne, ce qui signifie un ensemble mis en œuvre comme table de hachage. Comme d'habitude, les "buckets" pour les collisions (après le hash & modulo) sont des listes de cellules liées, chacune contenant un pstring pointeur et un pointeur vers la cellule suivante. Le seul détail spécial est que les cellules elles-mêmes sont stockées dans un tableau, au lieu d'être allouées n'importe où sur le tas [1]. J'espère que la photo est claire. Voici la définition de Cell:

typedef struct SCell { 
    PString  * pstr; 
    struct SCell * next; 
} Cell; 

Tout semblait bien fonctionner, y compris une batterie de tests de la piscine elle-même. Maintenant, lors du test d'une routine pstring (recherche), j'ai remarqué une chaîne modifiée. Après quelques recherches, j'ai finalement deviné que le problème est lié à la croissance de la piscine, et pourrait finalement réduire le problème autour de la croissance du réseau de cellules (donc, bien avant la redistribution des cellules dans les listes). Voici les lignes d'empreintes de débogage autour de cette croissance, avec une copie de la routine show_pool produisant la sortie (juste montre les chaînes), et la sortie elle-même:

static void pool_grow (StringPool * pool, uint n_new) { 
    ... 
    // Grow arrays: 
    show_pool(pool); ///////////////////// 
    pool->cells = realloc(pool->cells, pool->n_cells * sizeof(Cell)); 
    check_mem(pool->cells); 
    show_pool(pool); //////////////////// 
    ... 

static void show_pool (StringPool * pool) { 
    if (pool->n == 0) { 
     printfl("{}"); 
     return; 
    } 

    printf("pool   : {\"%s\"", pool->cells[0].pstr->bytes); 

    PString * pstr; 
    uint i; 
    for (i = 1; i < pool->n; i++) { 
     pstr = pool->cells[i].pstr; 
     printf(", \"%s\"", pstr->bytes); 
    } 

    printl("}"); 
} 

// output: 
pool   : {"", "abc", "b", "abcXXXabcXXX"} 
pool   : {"", "abc", "b", "abcXXXabcXXXI"} 

Comme vous pouvez le voir, la dernière chaîne stockée a un octet supplémentaire 'I'. Puisque entre-temps je ne fais qu'appeler realloc, je me trouve un peu bloqué pour un débogage plus poussé; et penser dur n'aide pas à éclairer ce mystère. (Notez que les cellules contiennent juste pstring pointeurs, alors comment la croissance de la matrice de cellules peut-elle modifier les octets de chaîne?) Aussi, je suis bluffé par le fait qu'il semble y avoir un NUL assez pratique juste après le mystérieux 'je', puisque printf s'arrête là.

Merci. Pouvez-vous m'aider?

[1] Il n'y a pas de raison particulière de le faire ici, avec un pool de chaînes. Je le fais habituellement pour obtenir gratuitement un ensemble ordonné ou une carte, et en plus la localité de référence. (La seule tête est que le réseau de cellules doit se développer en plus de la gamme de godets, mais on peut réduire le nombre de cultivations par prédimensionnement.)

+1

Veuillez enlever tout le fouillis et ne laisser que les informations essentielles. Et "Pouvez-vous aider?" Est votre question? – qrdl

+0

Pour commencer, 'pool-> cells = realloc (pool-> cells, ...)' est extrêmement mauvais usage de 'realloc'. – netcoder

+0

@netcoder Vous faites référence à la fuite de mémoire lorsque 'realloc()' renvoie NULL. "Extrêmement" est un peu fort. Ce n'est pas un mauvais usage si l'intention est de se terminer immédiatement lorsque 'realloc()' échoue, auquel cas la fuite est seulement pour le temps nécessaire à la sortie du programme. –

Répondre

2

Depuis size ne comprend pas la terminaison null,

mem[PSTRING_OFFSET + size] = NUL; 

est invalide. Tous les autres problèmes découlent de cela.

+0

Voilà, merci ecatmur! J'ai réécrit des morceaux de code à nettoyer, évidemment trop tôt ce matin, et j'ai raté le +1 ... –