2

I am learning about linked lists and how to create them in C with structs and pointers. I have an example below. From my understanding the called push() passes the beginning memory location of our struct where the head node lies as an argument. The parameter of our push() function takes a struct node as a pointer to pointer so it is passed as a reference, not an actual copy. So the first pointer of our struct node** headref is just a pointer to the memory location of our head node and the second pointer points to the value, which is the next memory location that the head node points to. We create a new node called newnode inside our struct node by assigning it some memory. We then create an int type data inside this node.

Okay assuming everything I said is correct, the next part is what i am confused on.

newNode->next= *headRef; 

This line from what i can understand dereferences the headref so this would just have the headref pointing to the head node. Then we have a pointer operation where what the headref is pointing to will then also be what our pointer next will be pointing to. Based on that the pointer next in our new node(newnode) will be pointing to the head pointer.

The next line which i am also confused on is:

*headRef = newNode;

What the dereferenced headref pointer is pointing to, which is the head node, will be pointing now to our newnode.

Based on that there should be a new node called newnode with an int data and a next pointer linking our newnode to the head. Then the headref pointer(or is it the head node?) will point to the new node. I know this isn't correct because the pointer next of our newnode should be pointing to the second node so our newnode can be linked in the struct. I also don't believe that i am understanding the pointer to pointer and dereferencing in the above two lines of code.

Code:

void Push(struct node** headRef, int data) {
  struct node* newNode = malloc(sizeof(struct node));

  newNode->data = data;
  newNode->next = *headRef;
  *headRef = newNode;
}

void PushTest(void) {
  struct node* head = BuildTwoThree(); // suppose this returns the list {2, 3}

  Push(&head, 1);
  Push(&head, 13);
  // head is now the list {13, 1, 2, 3} 
}
Waqar
  • 8,558
  • 4
  • 35
  • 43
user2122810
  • 93
  • 1
  • 3
  • 11
  • 2
    What is the question, exactly? – aaaaaa123456789 Mar 01 '13 at 09:15
  • I'm pretty sure I can read -- it's kinda hard to write without being able to read to begin with. That question being answered, what I was asking was what your question about those lines was -- is it just a "how does this work?" thing, or is it a "why doesn't it do X?" thing? – aaaaaa123456789 Mar 01 '13 at 09:19
  • 1
    which part of my assumptions are wrong? I am clearly not reading those two lines correctly because what i am thinking doesn't link the head node to the newnode and the next pointer of the newnode to the second node(previously created before we created a newnode to be inserted). Sorry for being rude, just annoyed i can't understand this. – user2122810 Mar 01 '13 at 09:22
  • Apology accepted. I'll post the details about the code in an actual answer. – aaaaaa123456789 Mar 01 '13 at 09:27

4 Answers4

0

You are actually both correct and not correct at the same time. The push function adds a new node at the head of the list. After this function is called the new node is the new head, and the previous head node is now the second (next) node in the list. So your observations are correct, but your conclusion is not.

I recommend you step through the code in a debugger, while watching all pointers and their contents, to see what happens. It might make things clearer for you.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • So can we agree that: newNode->next = *headRef; the pointer next is pointing to the head node? and *headRef = newNode; Is what exactly? The head node is now the newnode? so this just flipped the head and the newnode and because the newnode's pointer next is linked to the head(now the old head) then the new head(previously newnode) is pointing to the first node(old head)? – user2122810 Mar 01 '13 at 09:31
  • @user2122810 `newNode->next` will point to `head`, and then `*headRef = newNode` will make head point to `newNode`. The `head` pointer when this function is called, now points to the new node added. Really, step through the code in a debugger while checking all variables and pointer. It's a great way of seeing what happens "in action". – Some programmer dude Mar 01 '13 at 09:57
0

Ok. I think I can explain.

head is the head pointer of linked list. headRef points to head. So *headRef is head pointer(pass by reference).

so newNode->next will now point to head of the struct ( which has value 2, thats why the nodes are getting inserted at front).

Now in this line *headRef = newNode; *headRef is assigned the value of newNode so the head is now changed to newNode in the original structure.

Again when you pass &head, you are passing the head which contains value 1 now.

dejavu
  • 3,236
  • 7
  • 35
  • 60
  • The only thing i am confused about what you said is newNode->next. We are derefencing the headRef so now it doesn't point to 2 but to the head only. No? – user2122810 Mar 01 '13 at 09:34
  • headRef does not point to the structure, it only points to the variable that points to that structure. When you dereference it, you get that variable that points to that structure. – izogfif Mar 01 '13 at 10:01
  • @user2122810 Yes. It points to head. Not 2. To get "2" you have to do *headRef->data – dejavu Mar 01 '13 at 10:33
0

Let's copy this here, for simpler reference:

1   void Push(struct node** headRef, int data) {
2     struct node* newNode = malloc(sizeof(struct node));
3     newNode->data = data;
4     newNode->next = *headRef;
5     *headRef = newNode;
6   }

For the sake of simplicity, I numbered the lines.

Now, headRef itself is just a pointer to the variable that held the header of the list -- therefore, it contains no useful information by itself. By dereferencing that pointer, you're gaining access to the contents of the variable itself (head in PushTest()). Therefore, *headRef is essentially the way you get access to head. Now, since head is the top node, so is *headRef -- they hold the same value, since they are the same address. What line 4 does is, assign the value of *headRef (i.e., the value of head) to the new node's next link. In the same fashion, line 5 assigns the new node to *headRef, which is the same as assigning it to head, since headRef is a pointer to head -- meaning that *headRef is the value of head.

The key point here is, headRef is a reference (a pointer) to head, so *headRef and head are equivalents (scope rules aside).

aaaaaa123456789
  • 5,541
  • 1
  • 20
  • 33
0
void Push(struct node** headRef, int data) {

headRef contains an address of address where struct node is located. It is an address of the head variable in PushTest function.

struct node* newNode = malloc(sizeof(struct node));

Here we created a newNode. It contains an address of memory where node struct is located.

newNode->data = data;

set the data of newNode to the value of the data parameter passed into the Push function - OK.

newNode->next = *headRef;

set the newNode->next to the address of the structure located in the head variable. For example, if we have written

 void Push(struct node* head, int data) {
 ...
 newNode->next = head;

Next, we need to change the head variable to the newNode. If head variable was passed by reference, we could simply write this, like in C++:

void Push(struct node* &head, int data) {
...
head = newNode;

But in plain C we have to pass the address where head variable is located, so we can write into that address the pointer to the structure newNode we created in the Push function:

*headRef = newNode;

is equivalent to the write the newNode pointer to the variable whose address is located inside the headRef variable

And there is a problem in your logic:

The parameter of our push() function takes a struct node as a pointer to pointer so it is passed as a reference, not an actual copy.

Actually, we pass a copy of temporary variable that contains an address of node variable, not the reference. There is pass-by-reference method in C++, it uses ampersand to declare that the variable passed to function is a reference, not a copy of original variable.

izogfif
  • 6,000
  • 2
  • 35
  • 25
  • Thank you for the detailed answer! I wish i could give everyone best answer but yours is the most detailed one. – user2122810 Mar 01 '13 at 14:58