Вопрос по c, matrix, memory-management, pointers – матрица int с указателями в C - путаница в распределении памяти

6

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

<code>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]);
}
</code>

Ваш Ответ

7   ответов
2


void free_matrix(int **matrix, int size_x)
{
    for(int i = 0; i < size_x; i++)
        free(matrix[i]);
    free(matrix);
}
Нельзя объявить переменную в цикле for в C. terminus
Можно в C99, но твой код не будет переносимым. Steve Jessop
1

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

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

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

Я просто хотел сделать это, чтобы показать, что память свободна, но теперь узнал, что ошибка была в том, что я думал там, не могу запустить valgrind, так как я на OS X и хотел узнать, действительно ли я его освободил. Fredrik
0

е еще одну функцию, подобную этой:

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

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

0

а не пытаться вызвать ошибку шины. Это потрясает и многими другими вещами.

Сэ

Я нахожусь на OS X, поэтому я не могу запустить valgrind, в противном случае я бы: / Вы знаете любую альтернативу, которая работает на Mac? Fredrik
9

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

Обратите внимание, что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 );
кажется, что цикл пока матрица [i]! = NULL не работает, даже если я не установил последний указатель на NULL, это совпадение / что-то другое плохо? Fredrik
Если вы выделите один дополнительный указатель и не установите его, онможет быт по умолчанию NULL, в зависимости от ОС (Windows обнуляет выделенную память, Unix - нет). Если это не так, вы выйдете за пределы выделенного массива и продолжите освобождать объекты до тех пор, пока не произойдет попадание в указатель NULL или (более вероятно) сбой. Graeme Perrow
calloc всегда устанавливает память в ноль. quinmars
0

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

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

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

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

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

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

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

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

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

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

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

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

Похожие вопросы