Странное поведение указателя указателя в связанном списке - PullRequest
1 голос
/ 22 сентября 2019

Давайте рассмотрим следующий код:

#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);
}

На практике я создаю связанный список и добавляю в него некоторые целочисленные значения.Однако, что я не могу понять, так это вывод функции `pointer_address '.В частности, я получаю

0x55871ac39360
0x55871ac39360

0x55871ac39340
0x55871ac39320

0x55871ac39320
0x55871ac39300

0x55871ac39300
0x55871ac392e0

0x55871ac392e0
0x55871ac392c0

0x55871ac392c0
0x55871ac392a0

0x55871ac392a0
0x55871ac39280

0x55871ac39280
0x55871ac39260

0x55871ac39260
(nil)

, конечно, конкретные значения различны для каждого запуска программы.Однако я не могу понять, почему, начиная со второй пары строк, в каждой паре печатное значение отличается.Они являются результатом

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

в обоих случаях.Более того, я замечаю, что начиная с третьей пары строк, верхняя соответствует последней из предыдущей пары.

ВОПРОС

Что происходит?

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ

Я знаю, что этот код не делает ничего интересного, и то же самое можно сделать другими способами.Однако мне интересно понять, что происходит с моим кодом.

1 Ответ

2 голосов
/ 22 сентября 2019

Ваша pointer_address функция:

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);
    }
}

Строка, которая создает странный результат:

p_current = &(next);

Это означает, что при изменении значения nextзначение *p_current также изменяется, поскольку они ссылаются на одну и ту же память.Таким образом, строка между вашими printf инструкциями изменяет значение *p_current:

next = (**p_current).next;

Более разумная реализация этой функции не будет использовать указатель на указатель, просто необходим указатель:

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 pointer_address(struct NODE *p_current) {
    while (p_current) {
        printf("%p\n", p_current);        
        p_current = p_current->next;
    }
}
...