Votre structure est plus compliquée par un niveau d'allocation dynamique de mémoire que ce qui est généralement nécessaire. Vous avez:
typedef struct a
{
unsigned long x;
...and other members...
} A, *PA;
typedef struct b
{
unsigned char length;
PA * x;
} B, *PB;
Le dernier membre de B est un struct a **
, ce qui pourrait être nécessaire, mais elle est rarement. Vous devriez probablement simplifier tout en utilisant:
typedef struct a
{
unsigned long x;
} A;
typedef struct b
{
unsigned length;
A *array;
} B;
Cette réécriture reflète un préjugé personnel contre typedefs pour les pointeurs (donc j'éliminais PA et PB). J'ai changé le type de length
en B à unsigned
de unsigned char
; L'utilisation de unsigned char
permet d'économiser de l'espace dans la conception illustrée, mais il est possible que vous économisiez de l'espace si vous conserviez la longueur allouée séparément de la longueur utilisée (mais même alors, j'utiliserais probablement unsigned short
plutôt que unsigned char
).Et, plus important encore, cela change le type de la matrice de sorte que vous n'avez pas de pointeur séparé pour chaque élément car le tableau contient les éléments eux-mêmes. Maintenant, parfois, vous avez vraiment besoin de gérer des tableaux de pointeurs. Mais c'est relativement inhabituel et cela complique définitivement la gestion de la mémoire.
Le code dans votre fonction test()
simplifie:
void init_b(unsigned char length, B *b)
{
b->length = length;
b->x = (A *)malloc(length*sizeof(*b->x));
for (int i = 0; i < length; i++)
b->x[i] = 0;
}
int main()
{
B b;
init_b(4, &b);
return 0;
}
En utilisant une boucle for
idiomatiques évite sortir des limites (un des problèmes dans le code d'origine). La boucle d'initialisation pour la mémoire allouée pourrait peut-être être remplacée par une opération memset()
, ou vous pouvez utiliser calloc()
au lieu de malloc()
.
Votre code initial définissait les pointeurs dans le tableau de pointeurs sur null; vous ne pouviez alors accéder à aucune donnée car il n'y avait pas de données; vous n'aviez pas alloué l'espace pour les valeurs réelles struct a
, juste l'espace pour un tableau de pointeurs à ces valeurs.
Bien sûr, le code doit vérifier si l'allocation de mémoire a échoué ou utiliser une fonction de couverture pour l'allocateur de mémoire qui garantit de ne jamais revenir si l'allocation de mémoire échoue. Il n'est pas sûr de supposer que l'allocation de mémoire réussira sans vérification quelque part. Les fonctions de couverture pour les allocateurs portent souvent des noms tels que xmalloc()
ou emalloc()
.
Quelqu'un d'autre a souligné que malloc.h
est non standard. Si vous utilisez les facilités de réglage qu'il fournit, ou les fonctionnalités de reporting qu'il fournit, alors malloc.h
est correct (mais il n'est pas disponible partout, donc il limite la portabilité de votre code). Cependant, la plupart du temps, la plupart du temps, il faut juste oublier malloc.h
et utiliser #include <stdlib.h>
à la place; en utilisant malloc.h
est un signe de réflexion des jours avant la norme C89, quand il n'y avait pas d'en-tête qui a déclaré malloc()
et al, et c'est un longtemps temps.
Voir également Freeing 2D array of stack; le code y était isomorphe avec ce code (êtes-vous dans la même classe?). Et j'ai recommandé et illustré la même simplification là-bas.
Cela ne fonctionnerait pas? Ce qui signifie, il ne compile pas? Ou ne se comporte pas comme prévu? –
'malloc.h' n'est pas un en-tête C standard. Utilisez 'stdlib.h'. –
Je ne pense pas qu'il s'agisse de fichiers de compilation ou d'en-tête. Je code avec VS2010, console vide de type de projet. –