Разница между malloc и памятью?


в чем разница между:

ptr = (char **) malloc (MAXELEMS * sizeof(char *));

или:

ptr = (char **) calloc (MAXELEMS, sizeof(char*));

когда это хорошая идея, чтобы использовать calloc над malloc или наоборот?

18 648

18 ответов:

calloc() ноль-инициализирует буфер, в то время как malloc() оставляет память неинициализированной.

EDIT:

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

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

calloc действительно касается памяти (она записывает на нее нули), и поэтому вы будете уверены, что ОС поддерживает выделение с фактической ОЗУ (или свопом). Именно поэтому он медленнее, чем malloc (мало того, что он должен обнулить его, ОС также должна найти подходящую область памяти возможно замена других процессов)

см., например,это так вопрос для дальнейшего обсуждения поведения 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 заключается в том, чтобы абстрагироваться от семантики копирования при записи для выделения памяти. Когда вы выделяете память с calloc, все это сопоставляется с одной и той же физической страницей, которая инициализируется до нуля. Когда какая-либо из страниц выделенной памяти записывается в физическую страницу выделяется. Это часто используется для создания огромных хэш-таблиц, например, так как части хэша пустые страницы не поддерживаются никакой дополнительной памятью (страницами); они с радостью указывают на одну страницу с нулевой инициализацией, которая может быть даже разделена между процессами.

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

вот один история оптимизации ПО ТЕМЕ: 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. Все остальное не гарантируется для правильной инициализации и может содержать так называемый ловушка представление, что вызывает неопределенное поведение. Другими словами, для любого типа, кроме unsigned char вышеупомянутый все-нулевой бит паттерн может представлять собой незаконное значение, представление ловушку.

позже, в одном из Технические исправления к стандарту C99, поведение было определено для всех целочисленных типов (что имеет смысл). Т. е. формально в текущем языке C вы можете инициализировать только целочисленные типы с помощью callocmemset(..., 0, ...)). Используя его для инициализации и все остальное в общем случае приводит к неопределенному поведению, с точки зрения языка Си.

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

наконец, еще одна важная деталь заключается в том, что calloc требуется для расчета конечного размера блока внутри, путем умножения размера элемента на количество элементов. А делать, что calloc необходимо следить за возможным арифметическим переполнением. Это приведет к неудачному выделению (нулевой указатель), если запрошенный размер блока не может быть правильно вычислен. Между тем, ваш malloc версия не делает никаких попыток следить за переполнением. Он выделит некоторый "непредсказуемый"объем памяти в случае переполнения.

из статьи бенчмаркинг весело с calloc () и нулевые страницы on блог Георга Хагера

при выделении памяти с помощью calloc (), объем запрашиваемой памяти не выделяется сразу. Вместо этого все страницы, принадлежащие блоку памяти, соединяются с одной страницей, содержащей все нули, с помощью некоторой магии MMU (ссылки ниже). Если такие страницы только читаются (что было верно для массивов b, c и d в исходной версии benchmark), данные предоставляются с одной нулевой страницы, которая – конечно же – помещается в кэш. Так много для ядер цикла с привязкой к памяти. Если страница записывается (независимо от того, как), возникает ошибка, "реальная" страница сопоставляется и нулевая страница копируется в память. Это называется copy-on-write, хорошо известный подход к оптимизации (который я даже преподавал несколько раз в своих лекциях на C++). После этого трюк с нулевым чтением больше не работает для этой страницы, и именно поэтому производительность была такой высокой понизьте после вставки-предположительно избыточного-цикла инициализации.

calloc обычно malloc+memset до 0

обычно немного лучше использовать malloc+memset явно, особенно, когда вы делаете что-то вроде:

ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));

что лучше, потому что sizeof(Item) известно компилятору во время компиляции, и компилятор в большинстве случаев заменит его наилучшими инструкциями к нулевой памяти. С другой стороны, если memset происходит calloc, размер параметра распределения не компилируется в calloc код и реальные memset часто вызывается, который обычно содержит код, чтобы сделать байт за байтом заполнить до длинной границы, чем цикл, чтобы заполнить память в sizeof(long) куски и, наконец, байт за байтом заполняют оставшееся пространство. Даже если распределитель достаточно умен, чтобы вызвать некоторые aligned_memset это все равно будет общая петля.

одно заметное исключение будет, когда вы делаете malloc / calloc очень большой кусок памяти (некоторые power_of_two килобайт) в этом случае выделение может быть сделано непосредственно из ядра. Поскольку ядра ОС обычно обнуляют всю память, которую они отдают по соображениям безопасности,достаточно умный calloc может просто вернуть ее с дополнительным обнулением. Опять же - если вы просто выделяете что-то, что вы знаете, мало, вам может быть лучше с производительностью malloc+memset.

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

void *malloc(size_t size);

malloc() не инициализирует выделенную память.

calloc() выделяет память, а также инициализирует выделяет память для всех битов ноль.

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 и инициализировать все это до нуля,

      int *ptr = (int *) calloc(10, (sizeof(int)));

сходство:

и malloc() и calloc () вернут void* по умолчанию, если они не являются приведенными типами .!

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

  • calloc() выделяет область памяти, длина будет произведением ее параметров. calloc заполняет память нулями и возвращает указатель на first байт. Если он не может найти достаточно места, он возвращает NULL указатель.

синтаксис: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block); то есть ptr_var=(type *)calloc(n,s);

  • malloc() выделяет один блок памяти требуемого размера и возвращает указатель на первый байт. Если ему не удается найти требуемый объем памяти, он возвращает нулевой указатель.

синтаксис: ptr_var=(cast_type *)malloc(Size_in_bytes); Элемент malloc() функция принимает один аргумент, который является количеством байтов для выделения, в то время как calloc() функция принимает два аргумента, один из которых-количество элементов, а другой-количество байтов, выделяемых для каждого из этих элементов. Кроме того,calloc() инициализирует выделенную память нулями, в то время как malloc() нет.

The calloc() функция, которая объявлена в <stdlib.h> заголовок предлагает несколько преимуществ по сравнению с

разница еще не упомянул: лимит в размере

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 Гбайт.

malloc (): выделяет запрошенный размер байтов и возвращает указатель первый байт выделенного пространства

calloc (): выделяет пространство для элементов массива, инициализирует до нуля, а затем возвращает указатель на память

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() так как это быстрее. Если требуется нулевая инициализация значений, используйте .

основные различия между malloc и calloc являются:

  1. malloc означает выделение памяти в то время как calloc означает непрерывные распределения.
  2. Танос берет только один аргумент, размер блока в то время как calloc принимает два аргумента, количество выделяемых блоков и размер каждого блока.

    ptr = (cast-type*) malloc (размер байта) // Мэллок

    ptr = (cast-type*)calloc (нет блоков, размер блока); // calloc

  3. 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() принимает один аргумент, в то время как calloc () принимает два.

во-вторых, malloc() не инициализирует выделенную память, а calloc() инициализирует выделенную память до нуля. Оба malloc и calloc используются в языке C для динамического выделения памяти они получают блоки памяти динамически.

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.