управление памятью функции malloc - PullRequest
1 голос
/ 04 июня 2019
Функция

malloc() формирует один блок памяти (скажем, 20 байтов, типизированный до int), так как же его можно использовать как массив из int блоков, например, как функцию calloc()? Разве это не должно использоваться для хранения только одного int значения в целых 20 байтов (20 * 8 бит)?

Ответы [ 4 ]

6 голосов
/ 04 июня 2019

(скажем, 20 байтов, типизированных до int)

Нет, возвращаемая память задается как указатель на void, неполный тип.

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

Цитирование C11, глава §7.22.3, Памятьфункции управления

[....] Указатель, возвращаемый в случае успешного выделения, соответствующим образом выравнивается, так что его можно назначить указателю на любой тип объекта с фундаментальным требованием выравнивания изатем используется для доступа к такому объекту или массиву таких объектов в выделенном пространстве (пока пространство не будет явно освобождено).[...] Возвращенный указатель указывает на начало (младший байтовый адрес) выделенного пространства.[....]

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

Уточнение: указатель не является массивом.

1 голос
/ 04 июня 2019

В C существует абстрактное понятие, формально известное как эффективный тип , означающее фактический тип данных, хранящихся в памяти.Это то, что компилятор отслеживает внутренне.

Большинство объектов в C имеют такой эффективный тип в момент объявления переменной, например, если мы введем int a;, тогда эффективный тип того, что хранится вa - это int.

То есть допустимо совершать злые поступки, подобные этим:

int a;
double* d = (double*)&a;
*(int*)d = 1;

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

Но когда мы вызываем malloc семейство функций, мы только говорим им зарезервировать nколичество байтов, без указания типа.Эта память гарантированно будет размещена в соседних ячейках памяти, но не более того.Единственная разница между malloc и calloc состоит в том, что последний устанавливает все значения в этой необработанной памяти на ноль.Ни одна из функций не знает ничего о типах или массивах.

Возвращенный кусок сырой памяти не имеет эффективного типа.До того момента, когда мы получим к нему доступ, он получит эффективный тип, который соответствует типу, используемому для доступа.

Так же, как и в предыдущем примере, не имеет значения, какой тип указателя мы установилиуказать на данные.Не имеет значения, пишем ли мы int* i = malloc(n); или bananas_t* b = malloc(n);, потому что указанная память еще не имеет типа.Он не будет получен до тех пор, пока мы не получим к нему доступ в первый раз.

0 голосов
/ 04 июня 2019

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

Размер непрерывного блока памяти, который вы выделили с помощью malloc, зависит от аргументаВы перешли в функцию malloc.http://www.cplusplus.com/reference/cstdlib/malloc/

Если вы хотите сохранить переменную int, вы сделаете это, определив тип указателя для типа int.

пример:

int p*; //pointer of type integer
size_t size = 20;
p = (int *) malloc(size); //returns to pointer p the memory address

после этого, используя указатель p, программист может получить доступ к значениям int (с точностью до 4 байтов).

calloc Единственное отличие от malloc заключается в том, чтоcalloc инициализирует все значения в этом блоке памяти на ноль.

0 голосов
/ 04 июня 2019

Нет ничего особенного в памяти, возвращаемой из malloc, по сравнению с памятью, возвращенной из calloc, кроме того факта, что байты блока памяти, возвращаемого calloc, инициализируются в 0. Память, возвращаемая malloc не должен использоваться для одного объекта, но может также использоваться для массива.

Это означает, что следующее эквивалентно:

 int *p1 = malloc(3 * sizeof(int));
 p1[0] = 1;
 p1[2] = 2;
 p1[3] = 3;
 ...
 int *p2 = calloc(3, sizeof(int));
 p2[0] = 1;
 p2[2] = 2;
 p2[3] = 3;

Оба вернут 3 * sizeof(int) байт памяти, которые можно использовать как массив int размера 3.

...