Я считаю, что есть две проблемы, связанные с тем, как вы думаете о распределении памяти.
Во-первых, вы, кажется, думаете о матрице как о выделенной в памяти форме визуальной матрицы. Но вы должны помнить, что компилятор не имеет понятия о матрице. Он также не знает, что память, которую вы выделяете в качестве отправной точки в строке матрицы, указывает на строку.
Во-вторых, вы должны явно указать компилятору, что вы хотите, а не полагаться на догадки компилятора, что также может привести к неопределенному поведению.
Я буду использовать 8-битные адреса, чтобы проиллюстрировать это.
Взять ptr = (char**)malloc(sizeof(char*) * 3)
, он может выделять адреса на 0x30 0x31 0x32
, каждый из которых будет хранить 8-битный тип. Предположим, что вы делаете *(ptr + 0) = malloc(4)
. Вызов malloc вернет указатель на четыре последовательных местоположения, где могут храниться символы. Предположим, он возвращает 0x40
, это означает, что все адреса 0x40 0x41 0x42 0x43
доступны для использования.
Однако значение по адресу 0x30 назначается 0x40, теперь помните, что указатель - это не тип, а двоичное представление числа, которое происходит для представления адреса. Следовательно, указатели не имеют такой роскоши, как деаллокатор (например, деструктор в C ++). Компилятор не знает, что это значение используется для доступа к выделенному адресу памяти, а скорее сохраняет это значение для вас. По этой причине вызов free(ptr)
освободит только адреса 0x30 0x31 0x32
.
Проще говоря, предположим, что у вас есть четыре целых числа, хранящихся в int*
как 1 2 3 4
, если компилятор попытается освободить четыре целых числа как адреса, вы столкнетесь с проблемами, поскольку буквально говорит компилятор с free
адресами 0x01 0x02 0x03 0x4
, который в старой системе будет иметь ужасные последствия, а в современных системах ваше приложение будет прекращено.
Поначалу это может показаться неудобным, однако это подразумевает некоторую гибкость в использовании этих указателей. Например, вы можете захотеть снова использовать ptr
вместо вызова free
и другого вызова malloc
, чтобы указать на другую матрицу.
Если при освобождении всех строк матрицы также освобождаются указатели на строки, вы можете столкнуться с ошибками сегментации, поскольку вы не знали о указателе, указывающем на этот адрес.
Говоря об этом, вы обязаны следить за этим и следить за тем, чтобы в куче не накапливались данные, на которые нет ссылок, указывающих на это.