Значение указателя теряется после вызова функции - C - PullRequest
0 голосов
/ 04 марта 2019
#include <stdlib.h>
#include <stdio.h>

typedef struct Node
{
    int *data;
}Node;


void AllocateNode(Node **newnode)
{
    *newnode = malloc(sizeof(int));
}


void insert(Node **p2head, int *p2data)
{
    if(*p2head == NULL)
    {
        AllocateNode(p2head);
        (**p2head).data = p2data;
    }
}

void ReadAll(Node **headptr)
{
    int x = 10;
    insert(headptr, &x);
}

void traverse(Node *headptr)
{
    printf("%d\n",*(headptr->data));
}

int main(void)
{
    Node *ListHead;
    ListHead = NULL;
    ReadAll(&ListHead);
    printf("%d\n",*(ListHead->data));

    traverse(ListHead);
}

Я очень смущен, потому что

printf("%d\n",*(ListHead->data));

выводит: 10 - желаемое значение, однако

printf("%d\n",*(headptr->data));

выводит: 0 - значение случайно теряется после прохожденияк функции перемещения, даже если она кажется правильно назначенной после всех других вызовов.

Ответы [ 2 ]

0 голосов
/ 04 марта 2019

В вашем коде есть несколько проблем:

В

void AllocateNode(Node **newnode)
{
    *newnode = malloc(sizeof(int));
}

*newnode - это Node*, поэтому оно должно быть

void AllocateNode(Node **newnode)
{
    *newnode = malloc(sizeof(Node));
}

В

void ReadAll(Node **headptr)
{
    int x = 10;
    insert(headptr, &x);
}

вы даете адрес x как локальную переменную для сохранения его в узле.

Весь доступ через этот указатель недопустим и имеет неопределенное поведение, когдавы выходите ReadAll

Одна возможность - выделить int

void ReadAll(Node **headptr)
{
    int * x = malloc(sizeof(int));

    *x = 10;
    insert(headptr, x);
}

После этих исправлений, компиляция и выполнение:

vxl15036 /tmp % gcc -pedantic -Wextra -g l.c
vxl15036 /tmp % ./a.out
10
10

Исполнение под valgrind

vxl15036 /tmp % valgrind ./a.out
==28709== Memcheck, a memory error detector
==28709== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==28709== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==28709== Command: ./a.out
==28709== 
10
10
==28709== 
==28709== HEAP SUMMARY:
==28709==     in use at exit: 12 bytes in 2 blocks
==28709==   total heap usage: 2 allocs, 0 frees, 12 bytes allocated
==28709== 
==28709== LEAK SUMMARY:
==28709==    definitely lost: 8 bytes in 1 blocks
==28709==    indirectly lost: 4 bytes in 1 blocks
==28709==      possibly lost: 0 bytes in 0 blocks
==28709==    still reachable: 0 bytes in 0 blocks
==28709==         suppressed: 0 bytes in 0 blocks
==28709== Rerun with --leak-check=full to see details of leaked memory
==28709== 
==28709== For counts of detected and suppressed errors, rerun with: -v
==28709== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
0 голосов
/ 04 марта 2019

Указатель на нестатическую локальную переменную передается из ReadAll() в insert() и сохраняется во вновь созданном узле.

Эта переменная становится недоступной после возврата из ReadAll() и разыменованияуказатель после этого вызывает неопределенное поведение .Это является причиной случайности.

Чтобы избежать этого, указатель на узел должен быть таким, который указывает на объект, который доступен даже после возврата из ReadAll().

Это может бытьархивируется путем динамического выделения

void ReadAll(Node **headptr)
{
    int *x = malloc(sizeof(int));
    *x = 10;
    insert(headptr, x);
}

или создания статической переменной.

void ReadAll(Node **headptr)
{
    static int x = 10;
    insert(headptr, &x);
}

Кроме того, как указал Питер, реализация Allocate() неверна.Размер выделения должен быть sizeof(Node), а не sizeof(int).

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