Разница в использовании между malloc и calloc - PullRequest
0 голосов
/ 30 ноября 2010
gcc 4.5.1 c89

Я написал этот исходный код для лучшего понимания malloc и calloc.

Я понимаю, но у меня есть только несколько вопросов.

dev = malloc(number * sizeof *devices);

равно этому кальку.Я не беспокоюсь об очистке памяти.

dev = calloc(number, sizeof *devices);

Что это такое, по сравнению с выполнением этого 5 раз в цикле while:

dev = malloc(sizeof *devices);

Я думаю, первое иВторое - создание указателя на 5 struct device.И третье - создание одного указателя на устройство struct?

Моя программа иллюстрирует это 3 различных метода, скомпилированных и запущенных с использованием valgrind --leak-check = full.

Большое спасибо за любые советы.

#include <stdio.h>
#include <stdlib.h>

struct Devices {
#define MAX_NAME_SIZE 80
    size_t id;
    char name[MAX_NAME_SIZE];
};

struct Devices* create_device(struct Devices *dev);
void destroy_device(struct Devices *dev);

int main(void)
{
    size_t num_devices = 5;
    size_t i = 0;
    struct Devices *device = NULL;
    struct Devices *dev_malloc = NULL;
    struct Devices *dev_calloc = NULL;

    for(i = 0; i < num_devices; i++) {
        device = create_device(device);
        /* Assign values */
        device->id = i + 1;
        sprintf(device->name, "Device%zu", device->id);
        /* Print values */
        printf("ID ----- [ %zu ]\n", device->id);
        printf("Name --- [ %s ]\n", device->name);
        /* Test free */
        destroy_device(device);
    }

    printf("\n");
    dev_malloc = malloc(num_devices * sizeof *dev_malloc);
    for(i = 0; i < num_devices; i++) {
        /* Assign values */
        dev_malloc->id = i + 1;
        sprintf(dev_malloc->name, "dev_malloc%zu", dev_malloc->id);
        /* Print values */
        printf("ID ----- [ %zu ]\n", dev_malloc->id);
        printf("Name --- [ %s ]\n", dev_malloc->name);
    }
    /* Test free */
    destroy_device(dev_malloc);

    printf("\n");
    dev_calloc = calloc(num_devices, sizeof *dev_calloc);
    for(i = 0; i < num_devices; i++) {
        /* Assign values */
        dev_calloc->id = i + 1;
        sprintf(dev_calloc->name, "dev_calloc%zu", dev_calloc->id);
        /* Print values */
        printf("ID ----- [ %zu ]\n", dev_calloc->id);
        printf("Name --- [ %s ]\n", dev_calloc->name);
    }
    /* Test free */
    destroy_device(dev_calloc);

    return 0;
}

struct Devices* create_device(struct Devices *dev)
{
    /* Not checking for memory error - just simple test */
    return dev = malloc(sizeof *dev);
}

void destroy_device(struct Devices *dev)
{
    if(dev != NULL) {
        free(dev);
    }
}

Ответы [ 7 ]

5 голосов
/ 30 ноября 2010

calloc(a,b) и malloc(a*b) эквивалентны, за исключением возможности арифметического переполнения или проблем типа и того факта, что calloc гарантирует, что память заполнена нулевым байтом. Либо выделенная память, которую можно использовать для массива a элементов, каждый из которых имеет размер b (или наоборот). С другой стороны, вызов malloc(b) a раз приведет к a отдельным объектам размером b, которые могут быть освобождены независимо и которые не в массиве (хотя вы можете сохранить их адреса в массиве указателей).

Надеюсь, это поможет.

4 голосов
/ 30 ноября 2010

malloc (n) выделяет n байтов плюс заполнение и служебные данные.

calloc (m, n) выделяет m * n байтов плюс заполнение и служебные данные, а затем обнуляет память.

Этоэто.

2 голосов
/ 30 ноября 2010

отредактировано для ясности

  • Полагаю, первое и второе создают указатель на 5 struct device. И третий - создание единого указателя на устройство struct?

Первый malloc(number * sizeof(*devices)) выделит достаточно памяти для хранения number из Device с. Как уже упоминалось, вы можете рассматривать этот блок как массив Device. Указатель, который вы вернете, будет указывать на начало блока.

int number = 5;
Device *ptr = malloc(number * sizeof(*ptr));
/* stuff */
free(ptr);

Второй, использующий calloc, делает то же самое, но при этом инициализирует память равной 0. Опять же, вы можете использовать этот блок как массив Device.

int number = 5;
Device *ptr = calloc(number, sizeof(*ptr));
/* stuff */
free(ptr);

Третий цикл, повторяющийся 5 раз, приведет к 5 различным указателям на 5 различных блоков, достаточно больших для хранения одного Device каждого. Это также означает, что каждый из 5 указателей должен free 'редактироваться индивидуально.

Device *ptrs[5];
for(int i = 0; i < 5; ++i)
{
    ptrs[i] = malloc(sizeof(*ptrs[i]));
}
/* stuff */
for(int i = 0; i < 5; ++i)
{
    free(ptrs[i]);
}
2 голосов
/ 30 ноября 2010

Первые два создают массив из 5 устройств в непрерывной памяти. Последний malloc, выполненный пять раз, создаст 5 отдельных устройств, которые не гарантированно находятся в непрерывной памяти.

1 голос
/ 01 декабря 2010

Посмотрите на реализацию calloc, чтобы увидеть различия.Это, наверное, что-то вроде этого:

// SIZE_MAX is defined in stdint.h from C99
void *calloc( size_t N, size_t S)
{
    void *ret;
    size_t NBYTES;

    // check for overflow of size_t type
    if (N > SIZE_MAX / S) return NULL;

    NBYTES = N * S;
    ret = malloc( NBYTES);
    if (ret != NULL)
    {
        memset( ret, 0, NBYTES);
    }

    return ret;
}
1 голос
/ 30 ноября 2010

Все три цикла в вашей программе используют только один объект struct Devices одновременно. Более поздние выделяют дополнительную память, как будто они собираются использовать несколько объектов, но затем продолжают перезаписывать начало этой памяти. Если вы попытаетесь использовать объект с идентификатором 1 после настройки объекта с идентификатором 2, вы обнаружите, что больше нет объекта с идентификатором 1.

Вместо этого вы можете сделать что-то подобное, чтобы рассматривать выделенную память как массив структур:

dev_malloc = malloc(num_devices * sizeof *dev_malloc);
for (i=0; i<num_devices; i++) {
    /* Assign values */   
    dev_malloc[i].id = i + 1;   
    sprintf(dev_malloc[i].name, "dev_malloc%zu", dev_malloc[i].id);   
    /* Print values */   
    printf("ID ----- [ %zu ]\n", dev_malloc[i].id);   
    printf("Name --- [ %s ]\n", dev_malloc[i].name);
}
free(dev_malloc);
0 голосов
/ 30 ноября 2010

Как вы указали, calloc обнуляет выделение памяти, а malloc - нет.

Каждый из ваших примеров 1 и 2 выделяет один непрерывный блок из пяти структур (и возвращает указатель на этот блок), тогда как пример 3 выделяет пять отдельных блоков по одной структуре каждый (и дает вам пять указателей, не связанных друг с другом.)

...