incapable de modifier la variable globale en c

J’apprends le C et, dans ce programme, j’essaie d’implémenter une simple liste chaînée. Chaque nœud de la liste contient un entier et un pointeur sur le nœud suivant. La head pointeur pointe vers le premier nœud de la liste, mais initialement la liste est vide, j’ai donc initialisé head = NULL .

Je veux faire deux opérations sur la liste – la peupler et l’imprimer.

Pour remplir la liste, j’appelle la fonction insert_node avec deux arguments: head et l’entier que je veux insérer.

Le problème est que j’ai besoin de la fonction insert_node pour changer la valeur de head (elle pointe donc vers la liste mise à jour au lieu de NULL). Je ne sais pas comment faire cela, alors j’ai fait de head une variable globale et j’essaie de changer sa valeur. Pour une raison quelconque, même si la valeur de head est modifiée dans la fonction insert_node , lorsque j’appelle à nouveau la fonction, head a toujours la valeur NULL.

Des questions:

  1. Pourquoi la valeur de la variable globale n’est-elle pas modifiée globalement?

  2. Je suis conscient que l’utilisation de variables globales n’est pas une bonne pratique, alors comment puis-je mettre à jour correctement le pointeur sur la liste? Je pensais insert_node fonction insert_node renvoie un pointeur à la liste. Est-ce une bonne solution?

 #include #include struct node { int data; struct node *link; }; void insert_node(struct node *head, int n); void print_list(struct node *head); struct node *head = NULL; main() { int i; for(i=1; idata); print_list(head->link); } return; } void insert_node(struct node *head, int n) { struct node N = {n, NULL}; struct node *next, *prev; int prev_data = 0; //case one: list is empty - point head to N, and set N.link to NULL if(head == NULL) head = &N; //case two: n is less than first element in the list: else if(n data) { N.link = head; head = &N; } else { next = head; //case three: N.data is equal to existing element, do nothing: while(next != NULL) { if(n == next->data) { printf("this element already exists.\n\n"); return; } prev = next; //save the current element next = next->link; //look at the next element } //case four: N.data is greater than last element: if(n > prev->data) { prev->link = &N; return; } //case five: N.data is in between list elements: next = head; while(next != NULL) { prev_data = next->data; //save the current element prev = next; //save pointer to current element next = next->link; //look at the next element if((n > prev_data) && (n data)) { prev->link = &N; N.link = next; return; } } } return; } 

    1. Parce que vous passez la head globale par valeur à la fonction insert_node() .
      Ensuite, la fonction insert_node() crée une variable locale (qui, d’ailleurs, porte également le nom head ce qui peut vous insert_node() , car elle est locale et non globale). Modifie cette head locale et ces modifications ne sont pas visibles dans la variable globale head . C’est ce qu’on appelle l’observation (la variable portant le même nom mais à l’intérieur de la scope locale est distincte de toute autre variable portant le même nom).
    2. Passez l’adresse de la tête à la fonction et faites en sorte que le paramètre de la fonction soit pointeur sur la structure.

    Déclaration

     void insert_node(struct node **ptr_to_head, int n); 

    Usage

     insert_node(&head, 5); 

    Maintenant, vous pouvez modifier head en déréférencant ptr_to_head dans votre fonction insert_node :

     (*ptr_to_head)=&new_node; ^ ^ | | head = value returned by malloc 

    Et oui, vous pouvez retourner la head de la fonction insert_node, mais n’oubliez pas de faire une affectation à la head dans la fonction principale.

    Vous avez ajouté une variable globale nommée head mais vous avez oublié de supprimer les parameters des fonctions insert_node, print_list, etc. portant le même nom. Le local a la priorité sur le global, vos assignations sont donc assignées au local et non au global.

    Supprimez les parameters portant le même nom et le problème disparaîtra.

    Je ne tolère cependant pas l’utilisation de globals 🙂

    Dans un commentaire, j’ai dit que le code d’insertion ne devrait pas nécessiter autant de cas que vous avez. Voici la preuve. Il comprend un code pour libérer la liste allouée. Notez qu’il y a moins de cas spéciaux (seulement trois: entrée dupliquée, insertion en tête, insertion ailleurs).

     #include  #include  struct node { int data; struct node *link; }; void insert_node(struct node **head, int n); void print_list(struct node *head); void free_list(struct node **phead); void test_insert(struct node **head, int n); int main(void) { struct node *head = NULL; free_list(&head); for (int i = 1; i < 5; i++) test_insert(&head, i*i); test_insert(&head, 0); test_insert(&head, 7); for (int i = 1; i < 6; i++) test_insert(&head, i*i - 3); test_insert(&head, 7); test_insert(&head, 0); free_list(&head); return 0; } void insert_node(struct node **phead, int n) { struct node *node = malloc(sizeof(*node)); if (node == NULL) { fprintf(stderr, "Failed to allocate node for %d\n", n); exit(1); } node->data = n; struct node *head = *phead; struct node *next = head; struct node *prev = NULL; while (next != NULL && n > next->data) { prev = next; next = next->link; } if (next != NULL && n == next->data) free(node); else { node->link = next; if (prev == NULL) *phead = node; else prev->link = node; } } void test_insert(struct node **head, int n) { printf("%2d:", n); insert_node(head, n); print_list(*head); } void print_list(struct node *head) { while (head != NULL) { printf(" %2i", head->data); head = head->link; } putchar('\n'); } void free_list(struct node **phead) { struct node *head = *phead; while (head != NULL) { struct node *next = head->link; free(head); head = next; } *phead = 0; } 

    Exemple de sortie:

    La valeur à gauche des deux points est la valeur ‘inséré’; la valeur à droite est la liste résultante.

      1: 1 4: 1 4 9: 1 4 9 16: 1 4 9 16 0: 0 1 4 9 16 7: 0 1 4 7 9 16 -2: -2 0 1 4 7 9 16 1: -2 0 1 4 7 9 16 6: -2 0 1 4 6 7 9 16 13: -2 0 1 4 6 7 9 13 16 22: -2 0 1 4 6 7 9 13 16 22 7: -2 0 1 4 6 7 9 13 16 22 0: -2 0 1 4 6 7 9 13 16 22