web-dev-qa-db-fra.com

définition auto-référentielle de la structure?

Cela fait très longtemps que je n’ai pas écrit C et je ne suis donc pas sûr de la manière dont je devrais faire ce genre de choses récursives ... Je voudrais que chaque cellule contienne une autre cellule, mais je reçois une erreur les lignes du "champ 'enfant' ont un type incomplet". Quoi de neuf?

typedef struct Cell {
  int isParent;
  Cell child;
} Cell;
119
Ziggy

Clairement, une cellule ne peut pas contenir une autre cellule car elle devient une récursion sans fin.

Cependant, une cellule PEUT contenir un pointeur sur une autre cellule.

typedef struct Cell {
  bool isParent;
  struct Cell* child;
} Cell;
167
Andrew Grant

En C, vous ne pouvez pas référencer le typedef que vous créez avec la structure elle-même. Vous devez utiliser le nom de la structure, comme dans le programme de test suivant:

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

typedef struct Cell {
  int cellSeq;
  struct Cell* next; /* 'tCell *next' will not work here */
} tCell;

int main(void) {
    int i;
    tCell *curr;
    tCell *first;
    tCell *last;

    /* Construct linked list, 100 down to 80. */

    first = malloc (sizeof (tCell));
    last = first;
    first->cellSeq = 100;
    first->next = NULL;
    for (i = 0; i < 20; i++) {
        curr = malloc (sizeof (tCell));
        curr->cellSeq = last->cellSeq - 1;
        curr->next = NULL;
        last->next = curr;
        last = curr;
    }

    /* Walk the list, printing sequence numbers. */

    curr = first;
    while (curr != NULL) {
        printf ("Sequence = %d\n", curr->cellSeq);
        curr = curr->next;
    }

    return 0;
}

Bien que ce soit probablement beaucoup plus compliqué que cela dans la norme, vous pouvez penser que le compilateur est au courant de struct Cell sur la première ligne de typedef mais ne connaissant pas tCell jusqu'à la dernière ligne :-) C'est comme ça que je me souviens de cette règle.

24
paxdiablo

Du point de vue théorique, les langues ne peuvent prendre en charge que les structures autoréférentielles et non les structures auto-inclusives.

15
Sundar

Il y a un moyen de contourner cela:

struct Cell {
  bool isParent;
  struct Cell* child;
};

struct Cell;
typedef struct Cell Cell;

Si vous le déclarez comme ceci, il indique correctement au compilateur que struct Cell et plain-ol'-cell sont identiques. Donc, vous pouvez utiliser Cell comme d'habitude. Reste à utiliser struct Cell dans la déclaration initiale elle-même.

12
Benjamin Horstman

Je sais que ce message est ancien, cependant, pour obtenir l'effet que vous recherchez, vous pouvez essayer les solutions suivantes:

#define TAKE_ADVANTAGE

/* Forward declaration of "struct Cell" as type Cell. */
typedef struct Cell Cell;

#ifdef TAKE_ADVANTAGE
/*
   Define Cell structure taking advantage of forward declaration.
*/
struct Cell
{
   int isParent;
   Cell *child;
};

#else

/*
   Or...you could define it as other posters have mentioned without taking
   advantage of the forward declaration.
*/
struct Cell
{
   int isParent;
   struct Cell *child;
};

#endif

/*
    Some code here...
*/

/* Use the Cell type. */
Cell newCell;

Dans l'un ou l'autre des deux cas mentionnés dans le fragment de code ci-dessus, vous DEVEZ déclarer votre structure de cellule enfant en tant que pointeur. Si vous ne le faites pas, vous obtiendrez le "type de champ incomplet". La raison en est que "struct Cell" doit être défini pour que le compilateur sache combien d’espace doit être alloué lorsqu’il est utilisé.

Si vous essayez d'utiliser "struct Cell" dans la définition de "struct Cell", le compilateur ne peut pas encore savoir combien d'espace "struct Cell" est supposé occuper. Cependant, le compilateur sait déjà combien d'espace prend un pointeur et (avec la déclaration forward), il sait que "Cell" est un type de "struct Cell" (bien qu'il ne connaisse pas encore la taille d'une "struct Cell" ) Ainsi, le compilateur peut définir une "Cell *" dans la structure en cours de définition.

8
Shawn

Passons en revue la définition de base de typedef. typedef permet de définir un alias pour un type de données existant, défini par l'utilisateur ou intégré.

typedef <data_type> <alias>;

par exemple

typedef int scores;

scores team1 = 99;

La confusion est ici avec la structure auto-référentielle, en raison d'un membre du même type de données qui n'a pas été défini auparavant. Donc, de façon standard, vous pouvez écrire votre code comme: -

//View 1
typedef struct{ bool isParent; struct Cell* child;} Cell;

//View 2
typedef struct{
  bool isParent;
  struct Cell* child;
} Cell;

//Other Available ways, define stucture and create typedef
struct Cell {
  bool isParent;
  struct Cell* child;
};

typedef struct Cell Cell;

Mais la dernière option augmente les lignes et les mots avec généralement nous ne voulons pas faire (nous sommes tellement paresseux que vous savez;)). Alors préférez View 2.

3
vineetv2821993

Une autre méthode pratique consiste à pré-typer la structure avec la balise de structure suivante:

//declare new type 'Node', as same as struct tag
typedef struct Node Node;
//struct with structure tag 'Node'
struct Node
{
int data;
//pointer to structure with custom type as same as struct tag
Node *nextNode;
};
//another pointer of custom type 'Node', same as struct tag
Node *node;
2
Keynes

Une structure qui contient une référence à elle-même. Une occurrence commune de ceci dans une structure qui décrit un nœud pour une liste de liens. Chaque nœud a besoin d'une référence au prochain nœud de la chaîne.

struct node
{
       int data;
       struct node *next; // <-self reference
};
1
DARSHINI DESAI

Toutes les réponses précédentes sont excellentes, j'ai juste pensé à expliquer pourquoi une structure ne peut pas contenir une instance de son propre type (pas une référence).

il est très important de noter que les structures sont des types 'value', c’est-à-dire qu’elles contiennent la valeur réelle. Ainsi, lorsque vous déclarez une structure, le compilateur doit décider de la quantité de mémoire à allouer à une instance de celle-ci. jusqu'à leur mémoire pour comprendre la mémoire totale de la structure, mais si le compilateur trouve une instance de la même structure à l'intérieur, il s'agit d'un paradoxe (c.-à-d. pour savoir combien de mémoire la structure A prend, vous devez décider combien de mémoire struct A prend!).

Mais les types de référence sont différents, si une structure 'A' contient une 'référence' à une instance de son propre type, bien que nous ne sachions pas encore combien de mémoire lui est allouée, nous savons combien de mémoire est allouée à une mémoire. adresse (c.-à-d. la référence).

HTH

1
m.eldehairy