Проблема с указателями на указатели в C - PullRequest
0 голосов
/ 24 января 2019

Я пытаюсь написать какой-то список в C, не создавая глобальную переменную для заголовка списка, и у меня возникают некоторые проблемы.

У меня изначально было это для моего кода:

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

struct Node {
    char *data;
    struct Node *next;
};

struct Node *init(struct Node *head) {
    head = malloc(sizeof(struct Node));
    head->data = "abc";
    head->next = NULL;

    return head;
}

struct Node *getHead(struct Node *head) {
    struct Node *retNode = NULL;

    if (head != NULL) {
        retNode = head;
        head = head->next;
    }

    return retNode;
}

int main(int argc, char **argv) {
    struct Node *head;
    head = init(head);
    printf("Head pointer before method:%p\n", head);

    getHead(head);
    printf("Head pointer after method:%p\n", head);
}

, который генерирует вывод:

Head pointer before method:0x7fffd36ad260  
Head pointer after method:0x7fffd36ad260

Я подумал, что это не сработало, потому что C - это передача по значению, что привело меня к мысли, что внутри метода была обнаружена идентичная копия с другим указателем. Однако когда я проверил указатель на Head внутри метода, я обнаружил, что он совпадает с исходным указателем head, поэтому кажется, что фактический указатель находится в методе. Я не понимаю, что здесь происходит, поэтому, если бы кто-то мог объяснить, почему указатель головы не обновляется, хотя там был бы тот же самый указатель, это было бы здорово.

Я думаю, что это должно работать, так как если у вас есть метод swap (int * a, int * b) и фактические указатели отправляются из основного, то изменения, сделанные внутри, будут влиять и на переменные снаружи. После просмотра онлайн люди говорили, что для этого нужно использовать указатели на указатели, хотя я не могу заставить это работать.

Попытка закодировать его следующим образом:

//... same code as before for other methods
struct Node *getHead(struct Node **head)
{
    struct Node *retNode = NULL;

    if (head != NULL)
    {
        retNode = *head;
        *head = *head->next;
    }

    return retNode;
}

int main(int argc, char **argv)
{
    struct Node *head;
    head = init(head);
    printf("Head pointer before method:%p\n", head);

    getHead(&head);
    printf("Head pointer after method:%p\n", head);
} 

Хотя при попытке скомпилировать я сталкиваюсь с ошибкой:

pointers.c:50:22: error: ‘*head’ is a pointer; did you mean to use ‘->’?
         *head = *head->next;

Я также в растерянности относительно того, почему эта ошибка выдается.

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Как и другие уже отмеченные, вам придется поставить *head в скобки из-за приоритета оператора.

Что у меня есть проблемы с пониманием, почему вы перезаписываете head с его преемником?Должна ли функция getHead лучше называться removeHead?

Также обратите внимание, что ваш head параметр в функции init не имеет никакого эффекта, так как он перезаписывается следующим malloc.

Я также рекомендую прочитать потрясающую статью о том, как ядро ​​Linux реализует эффективные списки с использованием struct embedding .Это восторг!

0 голосов
/ 24 января 2019

Передайте двойной указатель на getHead, так как вы пытаетесь обновить head в области, которая вызывает getHead.

struct Node *getHead(struct Node **head) {
    struct Node *retNode = NULL;

    if (head != NULL && *head != NULL) {
        retNode = *head;
        *head = (*head)->next;
    }

    return retNode;
}

Причина, по которой head является одним и тем же значением до и после вашего метода в первой попытке, заключается в том, что вы никогда не меняли значение head в main. Ваша функция getHead меняет свою локальную копию указателя head. Поэтому, если вы напечатаете head внутри getHead с первой попытки, вы увидите, что он указывает на другой адрес.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...