Как освободить мой двойной указатель, выделенный с помощью malloc в другой функции - PullRequest
0 голосов
/ 26 октября 2019

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

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

int main(){

    int ** matrix;
    int rows = 5;
    int cols = 6;
    matrix = createMatrix(rows, cols);
    printf("%d\n", matrix[2][3]);
    freeMatrix(matrix, rows);
    printf("%d\n", matrix[2][3]);
}
int** createMatrix(int row, int col){
    int **m = (int **)malloc(row * sizeof(int*));
    for(int x = 0; x < row; x++){
        m[x] = (int *)malloc(col * sizeof(int));
    }
    return m;
}
void freeMatriz(int **m, int row){
    for(int x = 0; x < row; x++){
        free(m[x]);
    }
    free(m);
}

Я пытался напечатать позицию, скажем, матрица [2] [3] до и после освобождения;но оба раза он печатает число, когда после печати этого делать не следует, поскольку это место в памяти должно быть освобождено, чего, очевидно, не происходит.

Ответы [ 2 ]

2 голосов
/ 26 октября 2019

кроме опечатки в

void freeMatriz(int **m, int row)
              ^

Это правильно освобождает память. Printf после освобождения матрицы должен фактически привести к нарушению доступа. Что при тестировании с НАМНОГО большей матрицей 1024x2048 это то, что происходит. Мои теории таковы ...

  1. Память еще не была восстановлена ​​и все еще находилась в пределах досягаемости программы ...
  2. Некоторая задержка в сборке мусора или что-то в этом роде ... lol

Я оставлю это кому-то, кто мог бы знать, почему второй printf работал с таким небольшим пространством памяти, выделенным для этого ..;) хотел бы знать точную причину ..

если вы пройдете через отладчик, вы увидите, что память освобождается должным образом, а если переходит через отладчик, второй printf приводит к нарушению доступа ... так что он должен иметь какое-то отношение кkernel ..:)

Если вы посмотрите на рабочий набор и распределение памяти в диспетчере задач и поместите систему («пауза») или getchar () (любой тип прерывания, который вы хотите) перед свободным.. Вы можете выделить большую матрицу, зарегистрироваться в диспетчере задач ... возобновить работу программы (с еще одним перерывом после бесплатного). и вы увидите, что память освобождается. :)

1 голос
/ 26 октября 2019

Ваши две основные проблемы:

  1. Вам не удалось проверить возврат каждого распределения, поэтому malloc мог потерпеть неудачу и у вас не было бы возможности узнать;и
  2. После выделения памяти для ваших целочисленных значений вы не можете инициализировать память, оставляя память, в которой хранятся все значения мусора, которые присутствовали в этом месте памяти (вы можете, и в случае ваших целочисленных распределений,используйте calloc для одновременного выделения и инициализации или memset для того же)

Ваша попытка получить доступ к matrix[2][3] до того, как free() просто получит доступ к неинициализированному 4-байты памяти, содержащие биты, которые там были. Ваша попытка доступа к matrix[2][3] после free() вызывает Неопределенное поведение . После free() вы больше не можете получить доступ к освобожденной памяти.

Если вы выделяете, вы должны проверить ... Это не вопрос , если malloc можетне удается вернуть NULL, это , когда malloc не может вернуть NULL. Чтобы обработать случай сбоя, вы всегда должны проверять возврат функции распределения (как вы делаете с каждой input функцией), которую вы используете. Это просто, если malloc возвращает NULL, выделение не выполнено. Так что просто проверьте, например,

int **creatematrix (int row, int col)
{
    int **m = malloc (row * sizeof *m);

    if (!m) {                   /* if you allocate -- you must VALIDATE */
        perror ("malloc-m");
        return NULL;
    }

    for (int x = 0; x < row; x++) {
        if (!(m[x] = malloc (col * sizeof *m[x]))) {    /* ditto */
            perror ("malloc-m[x]");
            while (x--)         /* on error free any allocated memory */
                free (m[x]);
            free (m);           /* before returing NULL */
            return NULL;
        }
    }

    return m;
}

( примечание: , прежде чем возвращать NULL, вы должны free() любую память, выделенную для этой точки, чтобы предотвратить утечку памяти при возвратеNULL)

В вашей вызывающей функции (main() здесь) вам необходимо проверить возвращение вашей функции creatematrix, чтобы определить успех / неудачу выделения - до Вы используете память, например,

int main (void) {

    int **matrix,
        rows = 5,
        cols = 6;

    if (!(matrix = creatematrix (rows, cols)))  /* VALIDATE allocations */
        exit (EXIT_FAILURE);

    for (int i = 0; i < rows; i++) {        /* loop initializing all values */
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = i * cols + j;
            printf (" %3d", matrix[i][j]);  /* output all values */
        }
        putchar ('\n');
    }

    freematrix (matrix, rows);              /* free all allocated memory */
}

Теперь вы можете free() всю память (что, кроме опечатки 'z' вместо 'x', вы делали правильно). В целом, вы можете сделать:

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

int **creatematrix (int row, int col)
{
    int **m = malloc (row * sizeof *m);

    if (!m) {                   /* if you allocate -- you must VALIDATE */
        perror ("malloc-m");
        return NULL;
    }

    for (int x = 0; x < row; x++) {
        if (!(m[x] = malloc (col * sizeof *m[x]))) {    /* ditto */
            perror ("malloc-m[x]");
            while (x--)         /* on error free any allocated memory */
                free (m[x]);
            free (m);           /* before returing NULL */
            return NULL;
        }
    }

    return m;
}

void freematrix (int **m, int row)
{
    for (int x = 0; x < row; x++)
        free (m[x]);

    free (m);
}

int main (void) {

    int **matrix,
        rows = 5,
        cols = 6;

    if (!(matrix = creatematrix (rows, cols)))  /* VALIDATE allocations */
        exit (EXIT_FAILURE);

    for (int i = 0; i < rows; i++) {        /* loop initializing all values */
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = i * cols + j;
            printf (" %3d", matrix[i][j]);  /* output all values */
        }
        putchar ('\n');
    }

    freematrix (matrix, rows);              /* free all allocated memory */
}

Пример использования / вывода

$ ./bin/freematrix
   0   1   2   3   4   5
   6   7   8   9  10  11
  12  13  14  15  16  17
  18  19  20  21  22  23
  24  25  26  27  28  29

Использование памяти / проверка ошибок

В любом написанном вами коде, который динамически распределяет память, у вас есть 2 обязанностей относительно любого выделенного блока памяти: (1) всегда сохраняйте указатель на начальный адрес для блокапамяти, так, (2) он может быть освобожден , когда он больше не нужен.

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

Для Linux valgrind - нормальный выбор. Для каждой платформы есть похожие проверки памяти. Все они просты в использовании, просто запустите вашу программу через нее.

$ valgrind ./bin/freematrix
==17080== Memcheck, a memory error detector
==17080== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==17080== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==17080== Command: ./bin/freematrix
==17080==
   0   1   2   3   4   5
   6   7   8   9  10  11
  12  13  14  15  16  17
  18  19  20  21  22  23
  24  25  26  27  28  29
==17080==
==17080== HEAP SUMMARY:
==17080==     in use at exit: 0 bytes in 0 blocks
==17080==   total heap usage: 6 allocs, 6 frees, 160 bytes allocated
==17080==
==17080== All heap blocks were freed -- no leaks are possible
==17080==
==17080== For counts of detected and suppressed errors, rerun with: -v
==17080== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

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

Посмотрите вещии дайте мне знать, если у вас есть дополнительные вопросы.

...