garder une trace de combien de mémoire malloc a alloué

Après une parsing rapide des questions connexes sur SO, j’ai déduit qu’il n’existait aucune fonction permettant de vérifier la quantité de mémoire allouée par malloc à un pointeur. J’essaie de reproduire certaines fonctionnalités de base de std :: ssortingng (principalement la taille dynamic) à l’aide de simples caractères * en C et je ne veux pas appeler realloc tout le temps. Je suppose que je devrai garder trace de la quantité de mémoire allouée. Afin de faire cela, je considère créer un typedef qui contiendra la chaîne elle-même et un entier avec la quantité de mémoire actuellement allouée, quelque chose comme ceci:

typedef struct { char * str; int mem; } my_ssortingng_t; 

Est-ce une solution optimale ou pouvez-vous suggérer quelque chose qui produira de meilleurs résultats? Merci d’avance pour votre aide.

Vous voudrez allouer l’espace pour la longueur et la chaîne dans le même bloc de mémoire. C’est peut-être ce que vous vouliez avec votre structure, mais vous avez réservé de l’espace uniquement pour un pointeur sur la chaîne.

Il doit y avoir un espace alloué pour contenir les caractères de la chaîne.

Par exemple:

 structure typedef
 {
     int num_chars;
     chaîne de caractères [];
 } my_ssortingng_t;

 my_ssortingng_t * alloc_mon_ssortingng (char * src)
 {
     my_ssortingng_t * p = NULL;
     int N_chars = strlen (src) + 1;

     p = malloc (N_chars + sizeof (my_ssortingng_t));
     si p)
     {
          p-> num_chars = N_chars;
          strcpy (p-> ssortingng, src);
     }
     retourne p;
 }

Dans mon exemple, pour accéder au pointeur sur votre chaîne, vous adressez le membre de ssortingng la ssortingng my_ssortingng_t :

 my_ssortingng_t * p = alloc_my_ssortingng ("hello free store.");
 printf ("La chaîne de% d octets est '% s' \ n", p-> num_chars, p-> chaîne);

Veillez à bien vous assurer que vous obtenez le pointeur de la chaîne en conséquence de l’allocation d’espace pour stocker les caractères. La ressource que vous allouez est la mémoire pour les caractères, le pointeur obtenu est une référence à la mémoire allouée.

Dans mon exemple, la mémoire allouée est disposée de manière séquentielle comme suit:

 + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- +
 |  00 |  00 |  00 |  11 |  'h' |  'e' |  'l' |  'l' |  'o' |  20 |  'f' |  'r' |  'e' |  'e' |  20 |  's' |  't' |  'o' |  'r' |  'e' |  '.' |  00 |
 + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- + ---- +
 ^^ ^
 ||  |
 p |  |
  p-> num_chars p-> chaîne

Notez que la valeur de p->ssortingng n’est pas stockée dans la mémoire allouée, elle se trouve à quatre octets du début de la mémoire allouée, immédiatement après l’entier (supposé 32 bits, quatre octets).

Votre compilateur peut exiger que vous déclariez le tableau C flexible en tant que:

 structure typedef
 {
     int num_chars;
     chaîne de caractères [0];
 } my_ssortingng_t;

mais la version sans le zéro est supposément conforme à C99.

Vous pouvez accomplir l’équivalent sans membre du tableau comme suit:

 structure typedef
 {
     int num_chars;
 } mystr2;

 char * str_of_mystr2 (mystr2 * ms)
 {
     return (char *) (ms + 1);
 }

 mystr2 * alloc_mystr2 (char * src)
 {
     mystr2 * p = NULL;
     size_t N_chars = strlen (src) + 1;

     if (N_chars num_chars = (int) N_chars;
          strcpy (str_of_mystr2 (p), src);
     }
     retourne p;
 } 

 printf ("La chaîne de% d octets est '% s' \ n", p-> num_chars, str_of_mystr2 (p));

Dans ce deuxième exemple, la valeur équivalente à p->ssortingng est calculée par str_of_mystr2() . Il aura approximativement la même valeur que le premier exemple, en fonction de la manière dont la fin des structures est compressée par les parameters de votre compilateur.

Bien que certains suggèrent de suivre la longueur dans une size_t je rechercherais un vieil article du Dr. Dobb sur les raisons de mon désaccord. Les valeurs de support supérieures à INT_MAX ont une valeur douteuse pour la correction de votre programme. En utilisant un int, vous pouvez écrire assert(p->num_chars >= 0); et avoir ce test quelque chose. Avec un unsigned, vous assert(p->num_chars < UINT_MAX / 2); le test équivalent, par exemple assert(p->num_chars < UINT_MAX / 2); Tant que vous écrivez du code contenant des vérifications sur les données d'exécution, l'utilisation d'un type signé peut être utile.

Par contre, si vous écrivez une bibliothèque qui gère des chaînes dépassant UINT_MAX / 2, je vous salue.

C’est la solution évidente. Et pendant que vous y êtes, vous voudrez peut-être avoir un membre struct qui conserve la quantité de mémoire allouée réellement utilisée. Cela vous évitera d’appeler strlen () tout le temps et vous permettrait de prendre en charge des chaînes non terminées par un caractère null, comme le fait la classe std :: ssortingng C ++.

C’est ce qui s’est passé au Pléistocène, et c’est comme cela que vous devriez le faire aujourd’hui. Malloc n’offre aucun mécanisme portable, pris en charge, pour interroger la taille d’un bloc alloué.

Une méthode plus courante consiste à envelopper malloc (et realloc) et à conserver une liste des tailles et des pointeurs.
De cette façon, vous n’avez pas besoin de changer les fonctions de chaîne.

écrire des fonctions d’emballage. Si vous utilisez malloc, vous devriez le faire quand même.

Pour un exemple, consultez “écriture de code solide”

Je pense que vous pourriez utiliser malloc_usable_size .