50 votes

Si free () connaît la longueur de mon tableau, pourquoi ne puis-je pas le demander dans mon propre code?

Je sais que c'est une convention à passer la longueur de tableaux alloués dynamiquement à des fonctions qui les manipulent:

void initializeAndFree(int* anArray, size_t length);

int main(){
    size_t arrayLength = 0;
    scanf("%d", &arrayLength);
    int* myArray = (int*)malloc(sizeof(int)*arrayLength);

    initializeAndFree(myArray, arrayLength);
}

void initializeAndFree(int* anArray, size_t length){
    int i = 0;
    for (i = 0; i < length; i++) {
        anArray[i] = 0;
    }
    free(anArray);
}

mais si il n'y a aucun moyen pour moi d'obtenir la longueur de la mémoire allouée à partir d'un pointeur, comment est - free() "automagiquement" savoir ce désallouer quand tout ce que je suis en train de faire, c'est le même pointeur? Pourquoi ne puis-je pas obtenir dans la magie, comme un programmeur en C?

Où est - free() obtenir son libre (har-har) de connaissances à partir de?

34voto

Matthew Flaschen Points 131723

Outre le point correct de Klatchko, à savoir que le standard ne le prévoit pas, de véritables implémentations malloc / free allouent souvent plus d’espace que ce que vous demandez. Par exemple, si vous demandez 12 octets, il peut en fournir 16 (voir Un allocateur de mémoire , qui indique que 16 est une taille commune). Donc, il n'est pas nécessaire de savoir que vous avez demandé 12 octets, mais simplement que cela vous a donné un bloc de 16 octets.

19voto

R Samuel Klatchko Points 44549

Vous ne pouvez pas l'obtenir parce que le comité C ne l'exige pas dans la norme.

Si vous êtes prêt à écrire du code non portable, vous pouvez avoir de la chance avec:

 *((size_t *)ptr - 1)
 

ou peut-être:

 *((size_t *)ptr - 2)
 

Mais si cela fonctionnera, cela dépendra exactement de l'endroit où la mise en œuvre de malloc vous utilisez stocke ces données.

10voto

N 1.1 Points 7687

Après la lecture de Klatchko de réponse, j'ai moi-même essayé et ptr[-1] magasins en effet le réel de la mémoire (généralement plus de la mémoire que nous avons demandé pour probablement sauver contre erreur de segmentation).

{
  char *a = malloc(1);
  printf("%u\n", ((size_t *)a)[-1]);   //prints 17
  free(a);
  exit(0);
}

Essayez avec différentes tailles, GCC alloue de la mémoire comme suit:

D'abord la mémoire allouée est de 17 octets.
La mémoire allouée est au moins 5 octets de plus que la taille demandée, si de plus n'est demandé, il alloue 8 octets de plus.

  • Si la taille est [0,12], la mémoire allouée est de 17 ans.
  • Si la taille est [13], la mémoire allouée est de 25.
  • Si la taille est [20], la mémoire allouée est de 25.
  • Si la taille est [21], la mémoire allouée est de 33.

9voto

Clifford Points 29933

Alors qu'il est possible d'obtenir les méta-données que l'allocateur de mémoire des lieux précédant le bloc alloué, cela ne fonctionne que si le pointeur est vraiment un pointeur vers un bloc alloué dynamiquement. Cela porterait gravement atteinte à l'utilité de la fonction exigeant que tous les arguments passés étaient des pointeurs vers des blocs plutôt que de dire un simple auto ou un tableau statique.

Le point est qu'il n'ya pas de portable chemin de l'inspection du pointeur de savoir quel type de mémoire il indique. Ainsi, alors que c'est une idée intéressante, il n'est pas particulièrement sûr de la proposition.

Une méthode qui est sûr et portable serait de réserver le premier mot de l'allocation pour tenir la longueur. GCC (et peut être quelques autres compilateurs) prend en charge un non-portable méthode de la mise en œuvre de cette aide d'une structure de longueur zéro tableau qui simplifie le code un peu par rapport à une solution portable:

typedef tSizedAlloc
{
    size_t length ;
    char* alloc[0] ;   // Compiler specific extension!!!
} ;

// Allocating a sized block
tSizedAlloc* blk = malloc( sizeof(tSizedAlloc) + length ) ;
blk->length = length ;

// Accessing the size and data information of the block
size_t blk_length = blk->length ;
char*  data = blk->alloc ;

4voto

merinoff Points 41

Je sais que ce thread est un peu vieux, mais je n'ai encore quelque chose à dire. Il y a une fonction (ou une macro, je n'ai pas vérifié la bibliothèque encore) malloc_usable_size() - obtient la taille du bloc de mémoire alloué à partir du tas. La page de man déclare que c'est uniquement pour le débogage, car il ne sort pas le numéro que vous avez demandé, mais le numéro qu'il a alloué, ce qui est un peu plus gros. Un avis c'est une extension GNU.

D'autre part, il peut même ne pas être nécessaire, parce que je crois que pour libérer de la mémoire morceau vous n'avez pas à connaître sa taille. Il suffit de retirer la poignée/descripteur/structure de qui est en charge de la partie.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X