MaPo
MaPo

Reputation: 781

Weird behavior of pointer of pointer in a linked list

Let us consider the following code:

#include <stdio.h>
#include <stdlib.h>

struct NODE {
    int value;
    struct NODE *next;
};

int prepend(struct NODE **head, int n){
    struct NODE *new_node = (struct NODE *)malloc(sizeof(struct NODE));
    if (!new_node) return -1;
    new_node->value = n;
    new_node->next = *head;
    *head = new_node;
    return 0;
}   

void pointer_address(struct NODE *head) {
    struct NODE **p_current = &head;
    struct NODE *next = NULL;
    while (*p_current) {
        printf("%p\n", (*p_current));        
        next = (**p_current).next;
        printf("%p\n\n", (*p_current));
        p_current = &(next);
    }
}

void delete_list(struct NODE *head) {
    struct NODE *current = head;
    struct NODE *next = NULL;
    while (current) {
        next = current->next;
        free(current);
        current = next;
    }
}

int main() {
    struct NODE *head = NULL;
    for(size_t i = 1; i < 10; i++) {
        if (prepend(&head, i)) {
            perror("Somenthing went wrong!\n");
            return -1;
        }
    }
    pointer_address(head);
    delete_list(head);
}

In practice I create a linked list, and I prepend some integer values in it. However what I cannot understand is the output of the function `pointer_address'. In particular I get

0x55871ac39360
0x55871ac39360

0x55871ac39340
0x55871ac39320

0x55871ac39320
0x55871ac39300

0x55871ac39300
0x55871ac392e0

0x55871ac392e0
0x55871ac392c0

0x55871ac392c0
0x55871ac392a0

0x55871ac392a0
0x55871ac39280

0x55871ac39280
0x55871ac39260

0x55871ac39260
(nil)

of course the particular values are different for every run of the program. What I really cannot understand is however why, starting from the second couple of lines, in each couple the printed value are different. They are the result of

printf("%p\n", (*p_current)); 

in both cases. I notice moreover that starting from the third couple of lines the upper one is equal to the last one of the preceding couple.

QUESTION

What is going on?

DISCLAIMER

I know that this code does not do anything interesting and the same things can be done in other ways. However my interest is to understand what is going on with my code.

Upvotes: 1

Views: 58

Answers (1)

Graeme
Graeme

Reputation: 3041

Your pointer_address function:

void pointer_address(struct NODE *head) {
    struct NODE **p_current = &head;
    struct NODE *next = NULL;
    while (*p_current) {
        printf("%p\n", (*p_current));        
        next = (**p_current).next;
        printf("%p\n\n", (*p_current));
        p_current = &(next);
    }
}

The line that is creating the strange result is:

p_current = &(next);

This means that when you change the value of next the value of *p_current also changes as they reference the same memory. So the line between your printf statements changes the value of *p_current:

next = (**p_current).next;

A saner implementation of this function would not use a pointer to pointer, just a pointer is all that is needed:

void pointer_address(struct NODE *head) {
    struct NODE *p_current = head;
    struct NODE *next = NULL;
    while (p_current) {
        printf("%p\n", p_current);        
        next = p_current->next;
        printf("%p\n\n", p_current);
        p_current = next;
    }
}

Or to simplify further:

void pointer_address(struct NODE *p_current) {
    while (p_current) {
        printf("%p\n", p_current);        
        p_current = p_current->next;
    }
}

Upvotes: 2

Related Questions