2010-07-03 6 views
2

J'ai deux fonctions C, qui fonctionnent essentiellement sur une structure de données de pile. Celui-ci pousse une valeur de type OBJ qui est en fait juste unsigned long au sommet de la pile. La pile est également cultivée si nécessaire.Comment insérer une valeur dans une position arbitraire dans un bloc de mémoire?

OBJ Quotation_push_(CzState *cz, CzQuotation *self, OBJ object) 
{ 
    if ((self->size + 1) > self->cap) { 
     self->items = (OBJ *)CZ_REALLOC(self->items, sizeof(OBJ) * (self->cap + 1) * 2); 
     self->cap = (self->cap + 1) * 2; 
    } 
    self->items[self->size++] = object; 
    return (OBJ)self; 
} 

La fonction suivante insère un OBJ dans une position arbitraire dans le tableau self->items. Essayez comme je le ferais, ça ne fonctionnera pas correctement. J'utilise Quotation_push_ ici avec une valeur fictive pour obtenir le comportement de croissance automatique. Le problème est que je vois toujours la valeur factice CZ_NIL à la fin de la matrice, avec l'élément que j'essaie d'insérer en écrasant ce qui est déjà dans la position. Voici ce que j'ai jusqu'à présent:

OBJ Quotation_insert_(CzState *cz, CzQuotation *self, OBJ object, int pos) 
{ 
    printf("have to move %d OBJ from %d to %d\n", self->size - pos, pos, pos + 1); 
    Quotation_push_(cz, self, CZ_NIL); 
    memmove(self->items + ((pos + 1) * sizeof(OBJ)), self->items + (pos * sizeof(OBJ)), sizeof(OBJ) * (self->size - pos)); 
    self->items[pos] = object; 
    return (OBJ)self; 
} 

Je ne reçois pas des erreurs de segmentation ou d'erreurs, il ne fonctionne pas comme prévu. Des idées?

Répondre

3

mise à jour:

Il y a deux problèmes, à la fois dans l'appel à memmove.

La première est une erreur ponctuelle dans le nombre d'octets à déplacer. Le nombre exact serait:

sizeof(OBJ) * (self->size - pos - 1) 

Omettre -1 sera effectivement déplacer un trop grand nombre d'octets, placer votre nouvel objet CZ_NILpassé la fin du tampon.

Le second problème est plus important, mais plus subtil. Ajouter des entiers à un pointeur oblige le compilateur à exécuter pointer arithmetic, ce qui explique automatiquement la taille des objets pointés. Voir this question pour plus de détails. Voici la version courte: self->items est un tableau de OBJ, donc vous n'avez pas besoin d'inclure sizeof(OBJ) dans les deux premiers arguments à memmove.

Mettre le tout ensemble, l'appel de fonction appropriée ressemblerait à ceci:

memmove((self->items + pos + 1), 
     (self->items + pos), 
     sizeof(OBJ) * (self->size - pos - 1)); 
Questions connexes