2009-11-23 5 views
1

Je regarde un exemple de manuel d'une liste liée qui implémente une pile. Je ne comprends pas pourquoi utiliser un pointeur vers un pointeur vers la pile est nécessaire pour l'opération de poussée. Voir l'exemple suivant:Pourquoi utiliser un pointeur vers un pointeur vers la pile lors de la création d'une fonction de poussée?

bool push(Element **stack, void *data) 
{ 
    Element *elem = new Element; 
    if(!elem) return false; 

    elem->data = data; 
    elem->next = *stack; 
    *stack = elem; 
    return true; 
} 

Si quelqu'un peut aider à expliquer pourquoi le premier paramètre de la méthode de poussée est un pointeur vers un pointeur, je serais très heureux. Merci.

Incroyable, merci pour toute l'aide excellente.

+0

C doesn pas un nouveau k eyword. C++ fait. Cela dit, C++ avec jeter une exception sur un échec d'allocation de mémoire, il n'y a pas besoin de vérifier null. – GManNickG

+0

Gardez également à l'esprit que vous pouvez utiliser des références au lieu de pointeurs pour laisser le compilateur faire le sale boulot pour vous. – GManNickG

Répondre

8

La fonction doit modifier la valeur du pointeur d'élément. Elle a donc besoin d'un pointeur vers pointeur. Autrement dit, une fonction prend un pointeur de quelque chose quand elle a besoin de modifier cette chose.

Dans ce cas, ce quelque chose est un pointeur lui-même. Ainsi, la fonction finit par prendre un pointeur vers un pointeur.

+0

OK donc ... corrigez-moi si je me trompe: Si nous voulions simplement ajouter quelque chose à la fin de la liste chaînée (pas une fonction push, juste une fonction addItem), nous n'aurions pas besoin d'un pointeur vers un pointeur vers le liste? – Lou

+0

Typiquement, vous auriez un pointeur vers le dernier élément, et cela contiendrait un pointeur avec une valeur NULL, que vous voudriez changer. Donc, oui, vous auriez seulement besoin d'un pointeur vers le dernier élément. –

+0

Eh bien .. votre pointeur '** pile' dans ce cas est pour garder une trace de la position de la fin de la liste. Si vous n'avez pas besoin de garder trace d'une telle valeur, alors non, vous n'avez pas besoin de vous en préoccuper du tout lorsque vous ajoutez des éléments à votre liste liée. Vous pourriez éventuellement utiliser un pointeur sur la liste elle-même. – int3

0

Vous devrez mettre à jour un pointeur.

Une liste n'est rien d'autre qu'un pointeur vers un Element. Ainsi, vous pouvez réécrire cela

bool push(List* stack, void* data); 

voyez-vous pas que, dans le cas où vous ne seriez pas utiliser la double pointeur, votre déclaration réelle était

bool push(List stack, void* data); 

qui ne changerait pas la liste initiale à tout.

Mais tour à tour,

bool push(Element* &stack, ...) 

est bien aussi, car il vous permet des mises à jour.

4

Un pointeur est simplement une variable qui contient une valeur , cette valeur est une adresse de mémoire.

Un pointeur sur un pointeur est également simplement une variable qui contient une valeur. Cette valeur est l'adresse mémoire d'un pointeur.

Vous utilisez un pointeur vers un pointeur lorsque vous souhaitez modifier la valeur d'un pointeur.

//Not a very useful example, but shows what I mean... 
void getOffsetBy3Pointer(const char *pInput, char **pOutput) 
{ 
    *pOutput = pInput + 3; 
} 

Et vous appelez cette fonction comme ceci:

const char *p = "hi you"; 
char *pYou; 
getOffsetBy3Pointer(p, &pYou); 
assert(!stricmp(pYou, "you")); 

maintenant considérer ce qui se passerait si nous avons essayé de mettre en œuvre cette fonction avec un seul pointeur.

//Note: This is completely wrong 
void BadGetOffsetBy3Pointer(const char *pInput, char *pOutput) 
{ 
    //*pOutput refers to the first actual char element that pOutput points to. 
    pOutput = pInput + 3; 
    //pOutput now points to pInput + 3, but the variable we passed in remains distinct. 
} 

Et vous appelez cette fonction comme ceci:

const char *p = "hi you"; 
char *pYou = NULL; 
BadGetOffsetBy3Pointer(p, pYou); 
assert(pYou == NULL); 

Note dans la BadGetOffsetBy3Pointer, nous aurions pu changer quelques-uns des personnages, mais nous ne pouvions pas changer ce Pyou points.

0

La pile est représentée par un pointeur sur le dernier élément qui a été poussé dessus. Afin de changer la pile en y poussant un élément, ce pointeur doit être mis à jour, donc nous lui passons un pointeur vers la fonction push.

0

Regardez comment quelqu'un utiliser cette fonction push:

Data d1, d2; 

Stack *s = null; // s := null 
push(&s, &d1); // s := {d1}->null 
push(&s, &d2); // s:= {d2}->{d1}->null 

Maintenant, vous pouvez continuer à utiliser la variable s, qui a été modifiée par poussée pour pointer vers le haut de la pile de plus en plus.

Dans une pile, vous voulez toujours conserver un pointeur vers le haut, et la fonction de poussée facilite la maintenance de ce pointeur.

1

Une pile est essentiellement une liste chaînée de pointeurs. Chacun pointant vers celui en dessous. Parce que vous avez un nouvel élément et que vous voulez que cet élément apparaisse en premier dans votre liste (d'où le terme «pile», vous devez changer les points au début de votre liste)

Pour changer la valeur dans le "" pointeur à la tête de la liste », vous avez besoin de l'adresse de ce pointeur

1

en raison de cette ligne:..

*stack = elem; 

Fondamentalement, vous modifiez le pointeur d'origine dans la fonction

Questions connexes