使用下面的代码进行压栈操作时错误的:
void WrongPush(struct node* head, int data) {
struct node* newNode = malloc(sizeof(struct node));
newNode->data = data;
newNode->next = head;
head = newNode; // NO this line does not work!
}
void WrongPushTest() {
List head = BuildTwoThree();
WrongPush(head, 1); // try to push a 1 on front -- doesn't work
}
原因如下:
The problem is all in the very last line where the 3-Step Link Indictates that we change the head pointer to refer to the new node. What does the line head = newNode; do in WrongPush()?
It sets a head pointer, but not the right one. It sets the variable named head local to WrongPush(). It does not in any way change the
variable named head we really cared about which is back in the caller WrontPushTest().
We need Push() to be able to change some of the caller's memory— namely the head
variable. The traditional method to allow a function to change its caller's memory is to
pass a pointer to the caller's memory instead of a copy. So in C, to change an int in the
caller, pass a int* instead. To change a struct fraction, pass a struct
fraction* intead. To change an X, pass an X*. So in this case, the value we want to
change is struct node*, so we pass a struct node** instead. The two stars
(**) are a little scary, but really it's just a straight application of the rule. It just happens
that the value we want to change already has one star (*), so the parameter to change it
has two (**). Or put another way: the type of the head pointer is "pointer to a struct
node." In order to change that pointer, we need to pass a pointer to it, which will be a
"pointer to a pointer to a struct node".
Instead of defining WrongPush(struct node* head, int data); we define
Push(struct node** headRef, int data);. The first form passes a copy of
the head pointer. The second, correct form passes a pointer to the head pointer. The rule
is: to modify caller memory, pass a pointer to that memory. The parameter has the word
"ref" in it as a reminder that this is a "reference" (struct node**) pointer to the
head pointer instead of an ordinary (struct node*) copy of the head pointer.
正确的代码
Here are Push() and PushTest() written correctly. The list is passed via a pointer to the
head pointer. In the code, this amounts to use of '&' on the parameter in the caller and use
of '*' on the parameter in the callee. Inside Push(), the pointer to the head pointer is
named "headRef" instead of just "head" as a reminder that it is not just a simple head
pointer..
/*
Takes a list and a data value.
Creates a new link with the given data and pushes
it onto the front of the list.
The list is not passed in by its head pointer.
Instead the list is passed in as a "reference" pointer
to the head pointer -- this allows us
to modify the caller's memory.
*/
void Push(struct node** headRef, int data) {
struct node* newNode = malloc(sizeof(struct node));
newNode->data = data;
newNode->next = *headRef; // The '*' to dereferences back to the real head
*headRef = newNode; // ditto
}
void PushTest() {
struct node* head = BuildTwoThree();// suppose this returns the list {2, 3}
Push(&head, 1); // note the &
Push(&head, 13);
// head is now the list {13, 1, 2, 3}
}
与C语言稍微不同,C++的用法如下:
/*
Push() in C++ -- we just add a '&' to the right hand
side of the head parameter type, and the compiler makes
that parameter work by reference. So this code changes
the caller's memory, but no extra uses of '*' are necessary -- we just access "head" directly, and the compiler makes that
change reference back to the caller.
*/
void Push(struct node*& head, int data) {
struct node* newNode = malloc(sizeof(struct node));
newNode->data = data;
newNode->next = head; // No extra use of * necessary on head -- the compiler
head = newNode; // just takes care of it behind the scenes.
}
void PushTest() {
struct node* head = BuildTwoThree();// suppose this returns the list {2, 3}
Push(head, 1); // No extra use & necessary -- the compiler takes
Push(head, 13); // care of it here too. Head is being changed by
// these calls.
// head is now the list {13, 1, 2, 3}
}The memory drawing for the C++ case looks the same as for the C case. The difference is
that the C case, the *'s need to be taken care of in the code. In the C++ case, it's handled
invisibly in the code.
Hope that can help!
END