#c #pointers #void-pointers
#c #указатели #указатели void
Вопрос:
Я пишу код для освобождения общего двойного указателя в C ( void **ptr
). Как мне проверить, был ли указатель выделен через malloc
/ calloc
? Как мне освободить внутренние указатели? (Я научился делать это, используя for
цикл и получая количество элементов в указателе, но здесь мне это не дано.). Объявление функции является
void freeArray(void **ptr);
Как бы вы освободили этот указатель и проверили ошибки, чтобы убедиться, что вы не получите ошибку seg, утечку памяти или другую ошибку памяти?
Комментарии:
1. (a) Вы не проверяете, было ли что-то выделено
malloc
. Вы должны спроектировать свою программу так, чтобы она знала, какие объекты выделены, а какие нет. Стандарт C не предоставляет никаких средств для этого. (б) Вы не освобождаете указатели. Вы выделяете и освобождаете память. Еслиptr
ofvoid **ptr
указывает на указатели, которые указывают на выделенную память, вы освобождаете эту память, передавая каждый из этих указателей наfree
. Ваша программа должна быть спроектирована так, чтобы знать, сколько таких указателей существует.
Ответ №1:
Я пишу код для освобождения общего двойного указателя в C (void ** ptr).
Я считаю, что не существует такой вещи, как общий двойной указатель. Указатель — это просто указатель.
Как мне проверить, был ли указатель выделен через malloc / calloc?
Вы этого не сделаете. Указатель не выделяется. Выделяется память, и указателю присваивается адрес области.
Как мне освободить внутренние указатели? (Я научился делать это, используя цикл for и получая количество элементов в указателе, но здесь мне это не дано.). Объявление функции является
void freeArray(void **ptr);
«Внутренний указатель», я полагаю, не является подходящим описанием для этого использования.
В любом случае, сравните прототип вашей функции с обычным прототипом main()
int main(int argc, char** argv)
и вы увидите, что здесь чего-то не хватает.
Может быть, это будет более понятно, если вы напишете
void** ptr = NULL;
Вы объявляете ptr
. В качестве указателя. Но ptr
уже выделен. Он статичен. Может быть 4, может быть 8 байт. И он указывает на указатель на void
. Только это.
ptr
есть void**
, *ptr
есть void*
, **ptr
есть void
. При использовании ptr
в качестве блока указателей вы должны сделать то же самое, что система делает с main()
: создайте блок и сохраните свой собственный argc
, количество значений. Это ваша проблема, чтобы сделать это, или лучше, это ваша проблема, чтобы НЕ делать этого.
Попробуйте это:
void freeArray(int ptrc, void** ptr);
И держите эту пару всегда вместе и обновленной, поэтому часть «указания количества элементов в указателе» не представляет сложности.
Ответ №2:
Не существует переносимого способа определить, ptr
указывает на выделенный блок или нет, ни насколько велик этот блок, ни являются ли указатели в этом блоке действительными и указывают ли они на выделенную память.
freeArray
присваивается указатель на массив void
указателей. Поскольку нет информации о количестве указателей на free, необходимо сделать предположение:
-
либо количество указателей фиксировано. Допустим, ваша программа имеет дело с массивами из 3 указателей повсюду,
freeArray
можно предположить, что она освобождает 3 указателя… -
или массив может завершаться нулем, например,
argv
массив, переданныйmain
. Обратите внимание, однако, что этот конкретный массив строк не предназначен для освобождения таким образом.
Посмотрите на код, который распределяет массивы, и определите, какое соглашение используется.
Вот наивная реализация freeArray()
для выделенного массива указателей на выделенные блоки с нулевым завершением:
void freeArray(void **ptr) {
if (ptr) {
for (size_t i = 0; ptr[i]; i ) {
free(ptr[i]);
}
free(ptr);
}
}
Ответ №3:
освобождение указателя не меняет, выделен ли он с помощью malloc или calloc, если вы хотите освободить массив указателей, вы должны знать его длину до. если только вы не считаете, что последний элемент массива равен NULL, чтобы вы могли выполнять цикл и останавливаться при обнаружении NULL.