матрица int с указателями в C - путаница в распределении памяти - PullRequest
6 голосов
/ 20 сентября 2008

У меня возникли проблемы с созданием матрицы int без утечек памяти. Я хочу иметь возможность динамически преобразовывать данную (глобальную) матрицу в любой размер с помощью read_matrix (). Но потом я хочу иметь возможность освободить память позже. Так что в моем основном методе второй printf должен привести к ошибке шины, так как у него не должно быть выделенной памяти. Как бы я занялся созданием этого?

int**       first_matrix;
int**       second_matrix;
int**       result_matrix;

int** read_matrix(int size_x, int size_y)
{
    int** matrix;
    matrix = calloc(size_x, sizeof(int*));
    for(int i = 0;i<size_x;i++) {
        matrix[i] = calloc(size_y, sizeof(int));
    }
    for(int i = 0;i<size_x;i++) {
        for(int j = 0;j<size_y;j++) {
            matrix[i][j] = i*10+j;
        }
    }
    return matrix;
}

int main(int stackc, char** stack)
{
    first_matrix = read_matrix(10,10);
    printf("9:3 %d - 4:6 %d \n", first_matrix[9][3], first_matrix[4][6]);
    free(*first_matrix);
    free(first_matrix);
    printf("9:3 %d - 4:6 %d \n", first_matrix[9][3], first_matrix[4][6]);
}

Ответы [ 7 ]

9 голосов
/ 20 сентября 2008

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

Обратите внимание, что free( *first_matrix ) только для бесплатных first_matrix[0], а не для других массивов. Вы, вероятно, хотите, чтобы какой-то маркер обозначал последний массив (если только вы не будете всегда знать, когда освободите внешний массив, сколько внутренних массивов вы разместили). Что-то вроде:

int** read_matrix(int size_x, int size_y)
{
    int** matrix;
    matrix = calloc(size_x, 1+sizeof(int*)); // alloc one extra ptr
    for(int i = 0;i<size_x;i++) {
        matrix[i] = calloc(size_y, sizeof(int));
    }
    matrix[size_x] = NULL; // set the extra ptr to NULL
    for(int i = 0;i<size_x;i++) {
        for(int j = 0;j<size_y;j++) {
            matrix[i][j] = i*10+j;
        }
    }
    return matrix;
}

Затем, когда вы их освобождаете:

// keep looping until you find the NULL one
for( int i=0; first_matrix[i] != NULL; i++ ) {
    free( first_matrix[i] );
}
free( first_matrix );
2 голосов
/ 20 сентября 2008

Вам необходимо освободить каждый ряд по отдельности:


void free_matrix(int **matrix, int size_x)
{
    for(int i = 0; i < size_x; i++)
        free(matrix[i]);
    free(matrix);
}
1 голос
/ 20 сентября 2008

Освобождение памяти не заставляет ее уходить, это просто означает, что другое выделение может захватить тот же самый кусок памяти. Что бы вы ни положили в него, оно останется там до тех пор, пока что-то еще не заменит его.

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

Если вы хотите создать «ошибку шины», вам нужно указать на память, которая не принадлежит вашему процессу. Почему ты так хочешь?

0 голосов
/ 20 сентября 2008

Концепция, которую вы здесь упускаете, заключается в том, что для каждого calloc должна быть бесплатная. и это free должно быть применено к указателю, возвращенному из calloc.

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

для (int i = 0; i

затем, как только это будет сделано, освободите указатель, выделенный этим.

matrix = calloc (size_x, sizeof (int *));

То, как вы делаете это сейчас,

бесплатно (* first_matrix); бесплатно (first_matrix);

не будет делать то, что вы хотите.

0 голосов
/ 20 сентября 2008

Вы получаете утечки памяти, потому что вы освобождаете первую строку матрицы и список строк, но ни одну из строк с 1 по n. Вам нужно звонить бесплатно в цикле.

Однако есть несколько альтернатив: - Выделите sizeof (int *) строки + строки cols * sizeof (int) байтов и используйте первые байты для указателей строк. Таким образом, у вас есть только один кусок памяти для освобождения (и это проще для распределителя тоже) - Используйте структуру, которая содержит количество строк. Тогда вы можете полностью избежать списка строк (экономя память). Единственным недостатком является то, что вы должны использовать функцию, макрос или некоторую грязную запись для обращения к матрице.

Если вы выберете второй вариант, вы можете использовать структуру, подобную этой, в любом компиляторе C99, и снова вам нужно всего лишь выделить один блок памяти (с размерами numints * sizeof (int) + sizeof (int)):

struct matrix {
    int rows;
    int data[0];
}
0 голосов
/ 20 сентября 2008

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

Sam

0 голосов
/ 20 сентября 2008

Вы освободили только первую строку (или столбец) first_matrix. Напишите еще одну функцию, подобную этой:

void free_matrix(int **matrix, int rows)
{
    int i;
    for(i=0; i<rows; i++)
    {
        free(matrix[i]);
    }
    free(matrix);
}

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

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