C программирование: выделение указателя потеряно, даже если выполняется содержимое двойного указателя - PullRequest
1 голос
/ 23 марта 2020

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

В итоге Я пытаюсь настроить динамически распределяемую структуру для использования в программе, передавая код выделения другой функции за пределами main. Я знаю два способа сделать это: во-первых, заставить функцию возвращать указатель на выделенную структуру, например:

typeStruct *someFunction()

Или два, передать двойной указатель на структуру, разыменовать ее и выделить память на внутренний указатель. Например:

void someFunction(typeStruct **ptr)

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

К сожалению, похоже, что изменения сделаны по указанию указателя не выходите за рамки функции. Мне удалось воспроизвести мою проблему с помощью более простого примера программы. Вот код:

test. c:

#include "testheader.h"

int main() {

    char success = 0;
    test *t;
    printf("\nBefore setup (in Main), Test: %d", t);
    success = setupTest(&t);
    printf("\nAfter setup (in Main), Test: %d", t);

    free(t->numbers);
    free(t);

    return success;
}

testheader. c:

#include "testheader.h"

const int NUM_NUMBERS = 100;

char setupTest(test **ptr) {
    printf("\nBefore deference, Test: %d", *ptr);
    char flag = 0;
    test *t = *ptr;
    printf("\nBefore malloc, Test: %d", t);
    t = malloc(sizeof(test));
    printf("\nAfter malloc, Test: %d", t);
    if(t != NULL) {
        t->numbers = malloc(sizeof(int) * NUM_NUMBERS);
        if(t->numbers != NULL) {
            for(int i = 0; i < NUM_NUMBERS; ++i) t->numbers[i] = i;
        } else flag = 1;
    } else flag = 1;
    printf("\nEnd of setup, Test: %d", t);
    return flag;
}

testheader.h:

#ifndef TESTHEADER_H
#define TESTHEADER_H

#include <stdlib.h>
#include <stdio.h>
typedef struct test_t {

    int *numbers;

} test;

char setupTest(test **);

#endif

Вот как я его компилирую: g cc test. c testheader. c -o test.exe

Я использую g cc 5.1.0 для компиляции в git bash и консоль Windows 10 для запуска.

Вот мой вывод при запуске test.exe: Отладка консоли

И затем происходит сбой. Как можно видеть, внутренняя функция ведет себя так, как и ожидалось, хотя код за ее пределами не отражает распределение внутри, как если бы я только что передал сам указатель, а не передавал по ссылке с двойным указателем.

Есть ли что-то, чего мне здесь не хватает?

Диагноз:

Строки

test *t = *ptr;
t = malloc(sizeof(test));

Влияет только на локальную переменную t, а не на содержимое ** ptr.

Решение:

mallo c на содержимое ** ptr, а не на локальную переменную, чтобы при возврате выделение не выходило за пределы go , И поменяйте местами две строки.

*ptr = malloc(sizeof(test));
test *t = *ptr;

Ответы [ 2 ]

1 голос
/ 23 марта 2020
test *t = *ptr;

Я не знаю, думаете ли вы, что это настраивает какую-то постоянную ссылку между t и ptr (как в справочнике C ++), но это не так. Это просто присваивает последнее первому, которое становится спорным, когда вы добираетесь до:

t = malloc(sizeof(test));

, где t перезаписывается.

То, что вы пропустили после этой точки, это некоторые форма присваивания обратно к **ptr, что означает, что оно осталось с любым значением, которое имело при входе. Это, конечно, то, что вы видите.

Что вам нужно , чтобы сделать , это взять значение t и заполнить переданную переменную:

*ptr = t;

Вы также можете немного очистить свою функцию, гарантируя, что это атомы c - либо все должно быть сделано, либо ничего не должно быть выполнено ( особенно с точки зрения выделения памяти). Thius включает любые изменения в указателе, который вы передали по адресу:

int setupTest(test **ptr) {
    // Allocate a test structure. If fail, return indication.

    test *t = malloc(sizeof(test));
    if (t == NULL) {
        return 0;
    }

    // Allocate a numbers sub-structure. If fail,
    // free test structure and return indication.

    t->numbers = malloc(sizeof(int) * NUM_NUMBERS);
    if (t->numbers == NULL) {
        free(t);
        return 0;
    }

    // Have both structures, populate and return success.

    for (int i = 0; i < NUM_NUMBERS; ++i) {
        t->numbers[i] = i;
    }
    *ptr = t;
    return 1;
}
0 голосов
/ 23 марта 2020

Вы можете считать это следующим образом:
, потому что test *p => p = malloc()
так что test **p => *p = malloc()

это должно быть Mallo c to * ptr, но не птр.

char setupTest(test **ptr) {
    printf("\nBefore deference, Test: %d", *ptr);
    char flag = 0;
    test **t = ptr;
    printf("\nBefore malloc, Test: %d", *t);
    *t = malloc(sizeof(test));
    printf("\nAfter malloc, Test: %d", *t);
    if(t != NULL) {
        (*t)->numbers = malloc(sizeof(int) * NUM_NUMBERS);
        if((*t)->numbers != NULL) {
            for(int i = 0; i < NUM_NUMBERS; ++i) (*t)->numbers[i] = i;
        } else flag = 1;
    } else flag = 1;
    printf("\nEnd of setup, Test: %d", *t);
    return flag;
}

Или прямое мальло c до *ptr

char setupTest(test **ptr) {
    printf("\nBefore deference, Test: %d", *ptr);
    char flag = 0;
    printf("\nBefore malloc, Test: %d", *ptr);
    *ptr = malloc(sizeof(test));
    printf("\nAfter malloc, Test: %d", *ptr);
    if(*ptr != NULL) {
        (*ptr)->numbers = malloc(sizeof(int) * NUM_NUMBERS);
        if((*ptr)->numbers != NULL) {
            for(int i = 0; i < NUM_NUMBERS; ++i) (*ptr)->numbers[i] = i;
        } else flag = 1;
    } else flag = 1;
    printf("\nEnd of setup, Test: %d", *ptr);
    return flag;
}
...