2011-09-09 3 views
1

J'ai le code suivant que vous pouvez essayer d'utiliser c99 filename.c; ./a.outQuel est le problème avec realloc?

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

typedef unsigned long long int se_t; // stack element type 

se_t stack_size = 0; 
se_t *bottom_of_stack = NULL; 
#define top_of_stack (bottom_of_stack + stack_size * sizeof(se_t)) 

#define stack_infix(op) stack_push(stack_pop() #op stack_pop()) 
#define do_times(x) for(int _i=0; _i<x; _i++) 

void stack_push(se_t v) { 
    bottom_of_stack = realloc(bottom_of_stack, 
           ++stack_size * sizeof(se_t)); 
    *top_of_stack = v; 
} 

void stack_print() { 
    printf("stack(%d): \n", (int)stack_size); 
    for(se_t *i = bottom_of_stack; 
      i <= top_of_stack; 
      i += sizeof(se_t)) { 
     printf("%p: %d \n", (void*)i, (int)*i); 
    } 
} 

int main() { 
    int i = 2; 
    do_times(3) { 
     stack_push(i*=i); 
     stack_print(); 
    } 
} 

Je réallouer pile chaque fois que je pousse quelque chose. Voici la sortie (avec mes commentaires):

stack(1): 
0x105200820: 0 // realloc successfully allocated some memory for the first time 
0x105200860: 4 
stack(2): 
0x105200820: 0 // extended the memory range without moving it somewhere else 
0x105200860: 4 
0x1052008a0: 16 
stack(3): 
0x105200830: 0 // reallocated the memory to some other region (see the address) 
0x105200870: 0 // and failed for some reason to copy the old data! 
0x1052008b0: 0 // why?! 
0x1052008f0: 256 
+0

Il peut être utile de recommander 'do_times' d'utiliser la variable' i _ ## __ LINE__' au lieu de simplement 'i_'. (Personnellement, j'aime faire des choses comme '#define CAT_ (x, y) x ## y' /' #define CAT (x, y) CAT_ (x, y) '/' #define UNIQ (x) CAT (CAT (INTERNAL_, x), CAT (_DO_NOT_TOUCH_, __LINE __)) ') –

+0

Bonne idée avec' i _ ## __ LINE__'! Comment l'avez-vous trouvé? C'est presque comme "Gensym" dans Lisp. – Halst

+0

Et je suppose que 'UNIQ (x)' est une version 'corporative'? – Halst

Répondre

2

Utilisez ceci:

#define top_of_stack (bottom_of_stack + (stack_size - 1)) 

Comme il est, vous stockez des données après la fin de la somme allouée espace.

Oh, et changer cette ligne aussi:

i += sizeof(se_t)) { 

devrait être:

i++) { 

En raison de ce que pmg dit au sujet de l'arithmétique de pointeur.

+0

Cela signifie-t-il que je n'ai pas non plus besoin de 'sizeof' dans' realloc'? – Halst

+1

Non, vous avez besoin de 'sizeof' pour' realloc', car l'argument de taille de 'realloc' est toujours en octets. –

4

pointeur arithmétique utilise déjà sizeof (basetype). Lorsque vous faites

#define top_of_stack (bottom_of_stack + stack_size * sizeof(se_t)) 

vous multiplierez efficacement par sizeof (se_t) deux fois.

si bottom_of_stack a la valeur 0xF000 et stack_size est 2 et sizeof (se_t) est 0x10

bottom_of_stack + stack_size == 0xF020 
bottom_of_stack + stack_size * sizeof (se_t) == 0xF400 /* or whatever */