2011-04-06 2 views
2

Voici le morceau de code où je ne comprends pasTableau de pointeurs et plus en C

#include "malloc.h" 

/*some a type A and type for pointers to A*/ 
typedef struct a 
{ 
    unsigned long x; 
} A, *PA; 

/*some a type B and type for pointers to B*/ 
typedef struct b 
{ 
    unsigned char length; 
    /*array of pointers of type A variables*/ 
    PA * x; 
} B, *PB; 

void test(unsigned char length, PB b) 
{ 
    /*we can set length in B correctly*/ 

    b->length=length; 

    /*we can also allocate memory for the array of pointers*/ 

    b->x=(PA *)malloc(length*sizeof(PA)); 

    /*but we can't set pointers in x*/ 

    while(length!=0) 
     b->x[length--]=0; /*it just would not work*/ 
} 

int main() 
{ 
    B b; 
    test(4, &b); 
    return 0; 
} 

Quelqu'un peut-il me donner des détails sur le plan conceptuel pourquoi nous ne pouvons pas les pointeurs en tableau x ensemble test()?

+0

Cela ne fonctionnerait pas? Ce qui signifie, il ne compile pas? Ou ne se comporte pas comme prévu? –

+0

'malloc.h' n'est pas un en-tête C standard. Utilisez 'stdlib.h'. –

+0

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. –

Répondre

4

Sur la dernière ligne de test(), vous initialisez l'emplacement à la fin de votre tableau. Si votre longueur est 4, votre tableau a 4 pointes de long. b-> x [4] est le 5ème élément du tableau, car le 1er est b-> x [0]. Vous devez changer votre boucle while pour itérer sur les valeurs de 0 à longueur - 1.

+3

ce que vous voulez dire est qu'il pourrait faire - longueur au lieu de longueur-- non? –

+0

Oui, cela ferait fonctionner la boucle correctement. –

+0

@ Y.Z: Compilez-vous en mode débogage? –

-1

Je suppose que vous essayez de zéro toutes les positions longues non signés dans le tableau A qui est pointé au sein B.

est là un problème de précédence avec les opérateurs -> et [] ici?

Essayez:

(b->x)[length--] = 0; 

Et peut-être changer

typedef struct a 
{ 
    unsigned long x; 
} A, *PA; 

à

typedef struct a 
{ 
    unsigned long x; 
} A; 
typedef A * PA; 

etc

+1

Aucun de ces problèmes ne se pose. –

0

Je viens d'ajouter un printf dans le principal pour tester b.length et bx [] les valeurs et tout le travail. Juste ajouté comme ça printf("%d, %d %d %d %d", b.length, b.x[0], b.x[1], b.x[2], b.x[3]); avant le return.

Il donne 4, 0, 0, 0, 0 ce qui est ce que vous attendez non? Ou c'est une erreur algorithmique

1

Si vous voulez mettre à zéro chaque PA en b->x, alors écrire --length au lieu de length-- devrait faire le travail.
Évidemment, essayer de comprendre où appartient le -- est déroutant. Tu ferais mieux écrire:

unsigned i; 
for (i = 0; i < length; i++) 
    b->x[i] = 0; 

Mais en fait, dans ce cas, vous pouvez simplement utiliser:

memset(b->x, 0, length*sizeof(PA)); 
+0

Le problème est la différence entre l'opérateur avant et après la décrémentation. La différence est que --length opération va décrémenter la longueur d'abord, puis retourner la longueur de la valeur. length-- retournera la longueur en premier, puis diminuera la longueur de la valeur. – spade78

1

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.