0
gcc 4.5.1 c89

为了更好地理解 malloc 和 calloc,我编写了这个源代码。

我明白,但只是有几个问题。

dev = malloc(number * sizeof *devices);

等于这个calloc。我不关心清除内存。

dev = calloc(number, sizeof *devices);

与在 while 循环中执行 5 次相比,这到底是什么:

dev = malloc(sizeof *devices);

我猜第一个和第二个是创建一个指向 5 struct device 的指针。第三个是创建一个指向结构设备的指针?

我的程序说明了使用 valgrind --leak-check=full 编译和运行的这 3 种不同的方法。

非常感谢您的任何建议。

#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);
    }
}
4

7 回答 7

5

calloc(a,b)并且是等价的,除了算术溢出或类型问题的可能性,以及确保内存是零字节填充malloc(a*b)的事实。calloc分配的内存可用于a每个大小的元素数组b(反之亦然)。另一方面,调用malloc(b) atimes 将导致a单个对象的大小b可以独立释放并且不在数组中(尽管您可以将它们的地址存储在指针数组中)。

希望这可以帮助。

于 2010-11-30T17:48:06.253 回答
4

malloc(n) 分配 n 字节加上填充和开销。

calloc(m, n) 分配 m*n 字节加上填充和开销,然后将内存归零。

而已。

于 2010-11-30T17:46:55.067 回答
2

前两个在连续内存中创建一个包含 5 个设备的数组。最后一次 malloc 执行五次,将创建 5 个单独的设备,这些设备不能保证在连续内存中。

于 2010-11-30T17:44:45.583 回答
2

为清楚起见进行了编辑

  • 我猜第一个和第二个是创建一个指向 5 struct device 的指针。第三个是创建一个指向结构设备的指针?

第一个将分配足够的malloc(number * sizeof(*devices))内存来存储s。正如其他人所提到的,您可以将此块视为. 您返回的指针将指向块的开头。numberDeviceDevice

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'ed。

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]);
}
于 2010-11-30T17:46:13.787 回答
1

程序中的所有三个循环一次只使用一个struct Devices对象。后面的那些分配额外的内存,就好像他们将使用多个对象一样,但随后会继续覆盖该内存的开头。如果您在设置 ID 为 2 的对象后尝试使用 ID 为 1 的对象,您会发现不再有任何 ID 为 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);
于 2010-11-30T17:55:29.530 回答
1

查看 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;
}
于 2010-11-30T23:25:37.877 回答
0

正如您所指出的,calloc将分配的内存清零,而malloc没有。

您的示例 1 和 2 每个分配一个由五个结构组成的连续块(​​并返回一个指向该块的指针),而示例 3 分配五个单独的块,每个块包含一个结构(并为您提供五个彼此无关的指针。)

于 2010-11-30T17:44:02.943 回答