матрица int с указателями в C - путаница с распределением памяти

StackOverflow https://stackoverflow.com/questions/105653

Вопрос

У меня возникли некоторые проблемы с созданием матрицы 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]);
}
Это было полезно?

Решение

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

Обратите внимание , что 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 );

Другие советы

Вам нужно освободить каждую строку по отдельности:


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

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

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

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

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

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

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

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

Сэм

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

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

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

struct matrix {
    int rows;
    int data[0];
}

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

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

for(int i = 0;i < size_x;i++) { матрица [i] = calloc(size_y, sizeof(int));}

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

матрица = calloc(size_x, sizeof(int*));

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top