2015-12-19 3 views
3
int *p=(int*)malloc(sizeof(int)*n); 
free(p+n/2); 

В приведенном выше коде свободная функция освобождает всю последнюю половину массива или только ячейку p + n/2 "?C, free() и арифметика указателей

+4

он не будет dealloc ничего, вы должны передать ему указатель, который вы первоначально malloced –

+0

№. Вы можете только освободить весь блок (передав указатель на начало блока) – Alexguitar

+0

Общее предупреждение: не бросать результат 'malloc()'! – fuz

ответ

3

Нельзя передавать выражение, подобное (p + n/2), на free(). Вы можете передать указатель, возвращенный с одной из функций malloc(), на free(). Поэтому вам нужно освободить весь массив сразу.

0

В приведенном выше коде свободная функция освобождает всю последнюю половину массива или только p + n/2 "cell"?

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

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

бесплатно(): недопустимый указатель:

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

2

Ну, нет.

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

Ваш пример передаёт указатель, который не был возвращен malloc() - хотя он рассчитывается на основе этого указателя.

Результат вашего образца - неопределенное поведение.

Если вы хотите выделить память и затем изменить выделенный размер, найдите realloc().

3

Значение указателя, переданное в free, должно быть либо нулевым указателем, либо указателем на ранее выделенную память. В противном случае поведение не определено (это означает, что ваша программа может произойти сбой, или вы можете повредить внутренние структуры данных во время выполнения, или, что хуже всего, оно может вести себя так, как вы ожидаете).

Цитирование стандарта C11 (проект N1570 7.22.3.3p2):

free функция заставляет пространство указывает ptr быть освобождаться, то есть, доступны для дальнейшего распределения , Если ptr is null указатель, никаких действий не происходит.В противном случае, если аргумент не матча указателем ранее возвращенной функция управления памятью, или если пространство было высвобождено вызовом free или realloc, то поведение не определенно.

+0

Это ответ. –

+1

Хуже всего, он может вести себя так, как вы ожидаете, до тех пор, пока клиент не будет использовать ваше приложение, а затем все ад сломается :-) – gnasher729

0

Вы должны только передать указатель вернулся из malloc/calloc/realloc в free

Существует специальная практическая причина [в стороне от того, что стандарты говорят] для этого. freeдолжен знать длину байта выделенной области. Аналогично, realloc должен знать длину байта выделенная область.

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

struct memory_descriptor { 
    u32 magic;       // magic number 
    size_t length;      // memory area length in bytes 
    struct memory_descriptor *next;  // next memory area 
    struct memory_descriptor *prev;  // previous memory area 
}; 

Компоновка кусок памяти на самом деле выглядит следующим образом:

| memory_descriptor | usable memory area ... | 
        ^
         | 
         + pointer returned by malloc et. al. 

Когда вы free что-то, он принимает указатель и вычитает размер дескриптора, чтобы найти дескриптор-структуру и использует для определения размера области памяти.

Если вы передали что-то вроде pointer + 10, free не нашли дескриптор. Он будет использовать все, что есть. Вот почему в этом примере есть «поле магического числа», чтобы попытаться обнаружить это неправильное использование.

+0

Ну, например, на MacOS X и, возможно, в других реализациях обычно нет такого заголовка для небольших распределение. И никаких «последующих» и «пред» для любых распределений. – gnasher729

+0

@ gnasher729 Просто пример. Я написал несколько кучей выделений с нуля. Указатели могут быть полезны для проверки целостности. Если вы включите его [динамически], вы можете двунаправленный контрольный список и получить лучшую информацию о коррупции. Без отладки размер, возможно, достаточен [с магией]. При малом alloc это происходит из подпула [определяемого по диапазону адресов], который [выравнивается] на странице. Вы округлите, чтобы найти растровое изображение. Или «мощность 2» подпульных схем с «внеполосными» заголовками. Но обычно они требуют сканирования списка, чтобы найти заголовок подпункта, который описывает блок распределения фиксированного размера –