В чем разница между выполнением:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
или
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
Когда полезно использовать calloc над malloc или наоборот?
В чем разница между выполнением:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
или
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
Когда полезно использовать calloc над malloc или наоборот?
calloc()
zero инициализирует буфер, а malloc()
оставляет память неинициализированной.
EDIT:
Отбрасывание памяти может занять немного времени, поэтому вы, вероятно, захотите использовать malloc()
, если эта производительность является проблемой. Если инициализация памяти важнее, используйте calloc()
. Например, calloc()
может сэкономить вам вызов memset()
.
Менее известное различие заключается в том, что в операционных системах с оптимистичным распределением памяти, например Linux, указатель, возвращаемый malloc
, не поддерживается реальной памятью, пока программа не коснется его.
calloc
действительно касается памяти (он записывает нули на нем), и, таким образом, вы будете уверены, что ОС поддерживает выделение с помощью фактической RAM (или свопинга). Именно поэтому он медленнее, чем malloc (не только он должен его обнулить, но и операционная система должна найти подходящую область памяти, возможно, заменяя другие процессы)
См. например этот вопрос SO для дальнейшего обсуждения поведения malloc
Одним из часто забываемых преимуществ calloc
является то, что (соответствующие реализации) он поможет защитить вас от целых уязвимостей переполнения. Для сравнения:
size_t count = get_int32(file);
struct foo *bar = malloc(count * sizeof *bar);
против.
size_t count = get_int32(file);
struct foo *bar = calloc(count, sizeof *bar);
Первый может привести к крошечному распределению и последующему переполнению буфера, если count
больше, чем SIZE_MAX/sizeof *bar
. В этом случае последний будет автоматически терпеть неудачу, так как объект, который нельзя создать большим,
Конечно, вам, возможно, придется следить за несоответствующими реализациями, которые просто игнорируют возможность переполнения... Если это касается проблем на платформах, на которые вы нацелились, вам придется вручную выполнить проверку переполнения.
Документация делает calloc похожим на malloc, который просто выполняет нулевую инициализацию памяти; это не главное отличие! Идея calloc состоит в том, чтобы абстрагировать семантику copy-on-write для выделения памяти. Когда вы выделяете память с помощью calloc, она сопоставляется с той же самой физической страницей, которая инициализируется нулем. Когда выделяется какая-либо из страниц выделенной памяти на физическую страницу. Это часто используется для создания HUGE хэш-таблиц, например, поскольку части хэша, которые пусты, не поддерживаются дополнительной памятью (страницами); они с радостью указывают на единственную нулевую инициализацию страницы, которая может быть разделена между процессами.
Любая запись на виртуальный адрес отображается на страницу, если эта страница является нулевой страницей, выделяется другая физическая страница, копируется нулевая страница и поток управления возвращается клиенту. Это работает так же, как файлы с отображением памяти, виртуальная память и т.д. Работает.. он использует пейджинг.
Вот одна история оптимизации по теме: http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/
Нет разницы в размере выделенного блока памяти. calloc
просто заполняет блок памяти физическим шаблоном всех нулевых битов. На практике часто предполагается, что объекты, расположенные в блоке памяти, выделенные с помощью calloc
, имеют начальное значение, как если бы они были инициализированы литералом 0
, то есть целые числа должны иметь значение 0
, переменные с плавающей запятой - значение 0.0
, указатели - соответствующее значение нулевого указателя и т.д.
С педантичной точки зрения, однако, calloc
(а также memset(..., 0, ...)
) гарантируется только правильная инициализация (с нулями) объектов типа unsigned char
. Все остальное не гарантируется надлежащим образом инициализированным и может содержать так называемое ловушечное представление, которое вызывает поведение undefined. Другими словами, для любого типа, отличного от unsigned char
, вышеупомянутый all-zero-bits patterm может представлять недопустимое значение, ловушечное представление.
Позже, в одном из технических правил Corrigenda to C99, поведение было определено для всех целочисленных типов (что имеет смысл). То есть формально, на текущем языке C вы можете инициализировать только целые типы с помощью calloc
(и memset(..., 0, ...)
). Использование его для инициализации чего-либо еще в общем случае приводит к поведению undefined с точки зрения языка C.
На практике calloc
работает, как мы все знаем:), но хотите ли вы его использовать (учитывая выше), зависит от вас. Я лично предпочитаю полностью избегать этого, вместо этого используйте malloc
и выполните мою собственную инициализацию.
Наконец, еще одна важная деталь заключается в том, что calloc
требуется для вычисления размера конечного блока внутри, путем умножения размера элемента на количество элементов. При этом calloc
должен следить за возможным арифметическим переполнением. Это приведет к неудачному распределению (нулевой указатель), если запрошенный размер блока не может быть правильно рассчитан. Между тем, ваша версия malloc
не пытается наблюдать за переполнением. Он будет выделять некоторый "непредсказуемый" объем памяти в случае переполнения.
из статьи Бенчмаркинг с помощью calloc() и нулевых страниц в Блог Georg Hager
При распределении памяти с помощью calloc() объем запрошенной памяти не выделяется сразу. Вместо этого все страницы, принадлежащие блоку памяти, подключены к одной странице, содержащей все нули, с помощью некоторой MMU-магии (ссылки ниже). Если такие страницы только читаются (что верно для массивов b, c и d в исходной версии теста), данные предоставляются с единственной нулевой страницы, которая, конечно же, вписывается в кеш. Так много для ядер ядра, связанных с памятью. Если страница записывается (независимо от того, как), возникает ошибка, отображается "реальная" страница, а нулевая страница копируется в память. Это называется copy-on-write, хорошо известным подходом к оптимизации (который я даже много раз преподавал в своих лекциях на С++). После этого трюк с нулевым чтением больше не работает для этой страницы, и поэтому производительность была настолько ниже после вставки цикла предположительно избыточного цикла init.
calloc
обычно malloc+memset
до 0
Обычно лучше использовать malloc+memset
явно, особенно когда вы делаете что-то вроде:
ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));
Это лучше, потому что sizeof(Item)
знает компилятор во время компиляции, и компилятор в большинстве случаев заменяет его наилучшими возможными инструкциями для нулевой памяти. С другой стороны, если memset
происходит в calloc
, размер параметра распределения не компилируется в коде calloc
, и часто вызывается реальный memset
, который обычно содержит код для байтов -byte заполнить до длинной границы, чем цикл, чтобы заполнить память в sizeof(long)
кусках и, наконец, побайтовое заполнение оставшегося пространства. Даже если распределитель достаточно умен, чтобы вызвать некоторый aligned_memset
, он все равно будет общим циклом.
Одним из примечательных исключений будет то, что вы делаете malloc/calloc из очень большой части памяти (несколько power_of_two килобайт), и в этом случае распределение может производиться непосредственно из ядра. Поскольку ядра ОС, как правило, обнуляют всю память, которую они выдают по соображениям безопасности, достаточно разумный calloc может просто вернуть его с дополнительным обнулением. Опять же - если вы просто выделяете то, что, как вы знаете, мало, вам может быть лучше с malloc + memset с точки зрения производительности.
malloc()
выделяет блок памяти заданного размера (в байтах) и возвращает указатель на начало блока.
void *malloc(size_t size);
malloc()
не инициализирует выделенную память.
calloc()
выделяет память, а также инициализирует выделение памяти для всех битов 0.
void *calloc(size_t num, size_t size);
Разница 1:
malloc()
обычно выделяет блок памяти, и это инициализированный сегмент памяти.
calloc()
выделяет блок памяти и инициализирует весь блок памяти равным 0.
Разница 2:
Если вы рассмотрите синтаксис malloc()
, он будет принимать только 1 аргумент. Рассмотрим следующий пример ниже:
data_type ptr = (cast_type *)malloc( sizeof(data_type)*no_of_blocks );
Пример: если вы хотите выделить 10 блоков памяти для типа int,
int *ptr = (int *) malloc(sizeof(int) * 10 );
Если вы рассмотрите синтаксис calloc()
, он будет принимать 2 аргумента. Рассмотрим следующий пример ниже:
data_type ptr = (cast_type *)calloc(no_of_blocks, (sizeof(data_type)));
Пример: если вы хотите выделить 10 блоков памяти для типа int и инициализировать все это в ZERO,
int *ptr = (int *) calloc(10, (sizeof(int)));
Сходство:
malloc()
и calloc()
по умолчанию возвращают void *, если они не приводятся по типу.!
Есть два отличия.
Во-первых, это число аргументов. malloc()
принимает один аргумент (требуется память в байтах), а calloc()
- два аргумента.
Во-вторых, malloc()
не инициализирует выделенную память, а calloc()
инициализирует выделенную память ZERO.
calloc()
выделяет область памяти, длина будет продуктом ее параметров. calloc
заполняет память с помощью ZERO и возвращает указатель на первый байт. Если ему не удается найти достаточное пространство, он возвращает указатель NULL
.Синтаксис: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
т.е. ptr_var=(type *)calloc(n,s);
malloc()
выделяет один блок памяти REQUSTED SIZE и возвращает указатель на первый байт. Если он не находит требуемый объем памяти, он возвращает нулевой указатель.Синтаксис: ptr_var=(cast_type *)malloc(Size_in_bytes);
Функция malloc()
принимает один аргумент, который представляет собой количество байтов для распределения, тогда как функция calloc()
принимает два аргумента, одна из которых является числом элементов, а другая - количеством байтов для распределения для каждого из этих элементов, Кроме того, calloc()
инициализирует выделенное пространство нулями, а malloc()
- нет.
Функция calloc()
, объявленная в заголовке <stdlib.h>
, предлагает несколько преимуществ перед функцией malloc()
.
Разница пока не указана: ограничение размера
void *malloc(size_t size)
может выделяться только до SIZE_MAX
.
void *calloc(size_t nmemb, size_t size);
может выделять около SIZE_MAX*SIZE_MAX
.
Эта способность часто не используется во многих платформах с линейной адресацией. Такие системы ограничивают calloc()
nmemb * size <= SIZE_MAX
.
Рассмотрим тип 512 байтов, называемый disk_sector
, и код хочет использовать множество секторов. Здесь код может использовать только до SIZE_MAX/sizeof disk_sector
секторов.
size_t count = SIZE_MAX/sizeof disk_sector;
disk_sector *p = malloc(count * sizeof *p);
Рассмотрим следующее, которое допускает еще большее распределение.
size_t count = something_in_the_range(SIZE_MAX/sizeof disk_sector + 1, SIZE_MAX)
disk_sector *p = calloc(count, sizeof *p);
Теперь, если такая система может поставлять такое большое выделение, это другое дело. Сегодня больше не будет. Тем не менее, это происходило в течение многих лет, когда SIZE_MAX
составлял 65535. Учитывая закон Мура, предположите, что это произойдет около 2030 года с некоторыми моделями памяти с SIZE_MAX == 4294967295
и пулы памяти в 100 GBytes.
malloc()
и calloc()
- это функции из стандартной библиотеки C, которые позволяют распределять динамическую память, что означает, что они оба позволяют распределять память во время выполнения.
Их прототипы выглядят следующим образом:
void *malloc( size_t n);
void *calloc( size_t n, size_t t)
В основном существуют два различия между ними:
Поведение: malloc()
выделяет блок памяти, не инициализируя его, и чтение содержимого из этого блока приведет к значениям мусора. calloc()
, с другой стороны, выделяет блок памяти и инициализирует его нулями, и, очевидно, чтение содержимого этого блока приведет к нулям.
Синтаксис: malloc()
принимает 1 аргумент (размер, который нужно выделить), а calloc()
принимает два аргумента (количество блоков, которые должны быть выделены, и размер каждого блока).
Возвращаемое значение из обоих значений является указателем на выделенный блок памяти, если это необходимо. В противном случае возвращается NULL с указанием отказа в распределении памяти.
Пример:
int *arr;
// allocate memory for 10 integers with garbage values
arr = (int *)malloc(10 * sizeof(int));
// allocate memory for 10 integers and sets all of them to 0
arr = (int *)calloc(10, sizeof(int));
Такую же функциональность, как calloc()
можно достичь с помощью malloc()
и memset()
:
// allocate memory for 10 integers with garbage values
arr= (int *)malloc(10 * sizeof(int));
// set all of them to 0
memset(arr, 0, 10 * sizeof(int));
Обратите внимание, что malloc()
предпочтительно используется над calloc()
поскольку он быстрее. Если нулевая инициализация значений требуется, используйте calloc()
.
malloc(): выделяет запрошенный размер байтов и возвращает указатель на первый байт выделенного пространства
calloc(): выделяет пространство для элементов массива, инициализирует ноль и затем возвращает указатель на память
Основные отличия между malloc и calloc заключаются в следующем:
malloc принимает только один аргумент, размер блока, тогда как calloc принимает два аргумента, количество блоков, которые должны быть выделены, и размер каждого блока.
ptr = (cast-type *) malloc (размер байта)//malloc
ptr = (cast-type *) calloc (нет блоков, размер блока);//calloc
malloc не выполняет инициализацию памяти, и все адреса хранят значение мусора, тогда как calloc выполняет инициализацию памяти, а адреса инициализируются как значениями нуля или нулей.
Имя malloc и calloc() - это функции библиотеки, которые динамически распределяют память.
Это означает, что память выделяется во время выполнения (выполнение программы) из сегмента кучи.
Инициализация: malloc() выделяет блок памяти заданного размера (в байтах) и возвращает указатель на начало блока.
> malloc() doesn’t initialize the allocated memory. If we try to access
the content of memory block then we’ll get garbage values. void *
> malloc( size_t size );
> calloc() allocates the memory and also initializes the allocates
memory block to zero. If we try to access the content of these blocks
then we’ll get 0.
> void * calloc( size_t num, size_t size );
Несколько аргументов: В отличие от malloc(), calloc() принимает два аргумента: 1) Количество блоков, которые нужно выделить. 2) Размер каждого блока.
Самое важное:
Было бы лучше использовать malloc над calloc, если мы не хотим инициализации нуля, потому что malloc быстрее, чем calloc. Поэтому, если мы просто хотите скопировать некоторые вещи или сделать то, что не требует заполнение блоков нулями, то malloc будет лучше выбор.
char *ptr = (char *) malloc (n * sizeof(char));
просто выделяет n bytes
памяти без какой-либо инициализации (т.е. эти байты памяти будут содержать любые значения мусора).
char *ptr = (char *) malloc (n, sizeof(char));
Однако метод calloc()
в c инициализирует значение 0
для всех байтов занятой памяти в дополнение к функции, которую выполняет malloc()
.
Но кроме этого существует очень важное различие. При вызове malloc(x)
он выделяет память (равную x блокам) и возвращает указатель на выделенный первый байт. Тем не менее, он не проверяет, выделено ли ровно х блоков памяти. Это приведет к случаю переполнения памяти. Однако calloc()
проверяет размер выделения. Если это не удастся при распределении памяти или проверке выделенных байтов, она просто вернет значение null.
malloc() принимает один аргумент, а calloc() - двоичный.
Во-вторых, malloc() не инициализирует выделенную память, а calloc() инициализирует выделенную память для ZERO. Оба malloc и calloc используются на языке C для динамического распределения памяти, они динамически получают блоки памяти.
Нет блоков:
malloc() назначает один блок требуемой памяти,
calloc() Назначает несколько блоков запрошенной памяти
Инициализация:
malloc() не очищает и не инициализирует выделенную память.
calloc() инициализирует выделенную память нулем.
Скорость:
Скорость malloc() является быстрой.
calloc() скорость сравнительно медленная.
Синтекс:
void *malloc(size_t size); // syntex for malloc() function
void *calloc(size_t num, size_t size); // syntex for calloc() function
Аргумент:
Если вы рассмотрите синтаксис malloc(), он будет принимать только 1 аргумент.
Если вы рассмотрите синтаксис calloc(), он будет принимать 2 аргумента.
Способ распределения памяти ::
Функция malloc() назначает память нужного "размера" из доступной кучи.
Функция calloc() назначает память, размер которой равен 'num * size.
Значение по имени:
Название malloc означает приписываемый распределению памяти.
Название calloc означает непрерывное распределение.