2017-08-31 5 views
0

J'ai trouvé ce code sur un site Web pour insérer un nœud dans une liste chaînée au début de la liste.Quel est le point d'utiliser le pointeur sur le pointeur?

void push(struct Node** head_ref, int new_data) 
{ 
/* 1. allocate node */ 
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node)); 

/* 2. put in the data */ 
new_node->data = new_data; 

/* 3. Make next of new node as head */ 
new_node->next = (*head_ref); 

/* 4. move the head to point to the new node */ 
(*head_ref) = new_node; 
} 

C'est la fonction Call-

push(&head, 7); 

Ma question est pourquoi aller le long chemin en passant l'adresse d'un pointeur, puis extraire ensuite la valeur à l'adresse à l'intérieur de la fonction. Pourquoi ne pouvons-nous simplement passer le pointeur head dans la fonction, puis effectuer la cession comme -

new_node->next=head_ref; 

?

+0

[Jagged array] (https://en.wikipedia.org/wiki/Jagged_array) –

+2

Parce que la fonction modifie également la valeur de 'head_ref'. Puisque 'head' a un type de pointeur, vous devez passer un pointeur-à-pointeur pour' push' pour mettre à jour la valeur de 'head'. –

+0

Lire [this] (https://stackoverflow.com/a/897400/971127) – BLUEPIXY

Répondre

3

Si vous avez passé head et non &head, la ligne

(*head_ref) = new_node; 

devra être changé pour

head_ref = new_node; 

Cependant, ce sera un changement au niveau local dans la fonction. Il ne changera pas la valeur de head dans la fonction d'appel. Il y a deux problèmes avec cela:

  1. La fonction d'appel n'obtiendra jamais une liste de travail.
  2. La mémoire allouée dans la fonction sera une fuite de mémoire.
+0

Cela l'explique! Merci! – Vaibhav

+0

@Vaibhav, content d'avoir pu aider. –

0

La tête variable dans le programme appelant est un pointeur vers la tête de la liste. Vous avez besoin d'un pointeur vers cette variable pour la mettre à jour dans push(). Donc, vous passez un pointeur vers une variable qui contient un pointeur afin que vous puissiez mettre à jour cette variable.

2

Vous pouvez aussi écrire le code comme suit:

struct Node* push(struct Node* head_ref, int new_data) 
{ 
    struct Node* new_node = (struct Node*) malloc(sizeof(struct Node)); 
    new_node->data = new_data; 
    new_node->next = head_ref; 
    return new_node; 
} 

et l'appeler comme suit:

head = push(head, 7); 

Il réalise exactement la même chose, à savoir insère un nouveau nœud à la tête de la liste, puis met à jour head pour pointer vers ce nouveau nœud. Mais ce ne serait pas une solution aussi bonne, à mon avis, car elle permet à l'appelant de la fonction push() d'oublier d'assigner la valeur retournée à head, point auquel vous aurez des nœuds orphelins et finalement des fuites de mémoire.

+0

Ce n'est pas forcément pire non plus, il suffit d'ajouter l'exigence que le retour soit assigné. Vous pouvez avoir le meilleur des deux mondes (par exemple, la flexibilité de faire l'un ou l'autre), en passant un pointeur vers un pointeur pour taper ... renvoyer un pointeur vers le nœud courant ajouté (soit pour affectation, soit pour utilisation immédiate). Ni l'un ni l'autre n'est "techniquement" plus correct que l'autre tant que vous mettez à jour correctement la référence de la liste ':)' –

0

Tout cela est lié à un style de programmation que vous avez choisi. L'utilisation d'un ensemble de fonctions pour manipuler les listes rend le programme structurellement sain. De cette façon, vous le rendre plus lisible. Cela évitera également de couper-coller si vous devez manipuler la même liste à partir de plusieurs endroits ou manipuler plusieurs listes.

La façon dont vous organisez votre fonction dépend de vous. Personnellement, j'aime le chemin dans votre exemple. Dans ce cas, vous devez spécifier votre pointeur sur la tête seulement une fois dans l'argument. Si vous le renvoyez à partir de la fonction, vous risquez davantage d'utiliser un mauvais pointeur dans votre programme.

'C' a suffisamment d'outils pour écrire n'importe quel type de programme. Cependant parfois vous devez suivre des règles spécifiques pour les appliquer, comme une adresse d'un pointeur dans votre cas.Pas très pratique mais fiable et éprouvée. En tant que programmeur 'C', vous vous y habituerez rapidement.

Vous pouvez également regarder dans C++ qui a de meilleurs instruments pour rendre cela plus pratique.