malloc()
函数创建一个完整的内存块,然后返回第一个字节的指针。如果它只创建一个内存块,那么它只能存储一个元素对吧?但是malloc()
如何在一个内存块中存储多个元素,而当calloc()
创建多个内存块并且可以用作动态数组时,这是有意义的。
最佳答案
这是面包和黄油分配内存管理。无论为哪种类型的数据分配/重新分配,它的工作方式都是一样的。动态内存分配提供的三个标准函数是malloc/calloc/realloc
。虽然malloc/calloc
仅限于分配单个内存块,realloc
还可以调整内存块的大小,允许您使用malloc/calloc
分配一些初始存储块(或使用realloc
分配),然后使用realloc
来增加或减少分配的内存量。
与分配内存的每个函数调用一样,必须通过检查返回是否NULL
来验证调用是否成功。这就是为什么在使用realloc
时,总是使用临时指针!。因此,当(如果)由于内存不足而导致realloc
失败时,不会用realloc
丢失内存块的地址并创建内存泄漏来覆盖原始指针。
例如,如果您已分配给NULL
,则您不会将int *block = malloc (...)
作为:
block = realloc (block, 2 * n * sizeof *block); /* to double size */
如果
realloc
失败--返回什么,现在realloc
保存什么?(提示:block
)。因此,您可以使用一个临时指针,例如。/* always realloc to a temp pointer, or risk losing pointer */
void *tmp = realloc (block, 2 * n * sizeof *block); /* doubling size */
if (!tmp) { /* validate every allocation */
perror ("realloc-block");
/* handle error - original pointer still good */
}
block = tmp; /* assign reallocated block */
(注意:使用
NULL
是因为这是void *tmp
的返回类型。它可以有效地realloc
匹配int *tmp
的类型。关键是临时指针block
的类型必须与tmp
兼容,以便分配重新分配的块,例如block
。对于新的C程序员来说,在C语言中,任何指针都可以在没有显式转换的情况下转换到或从block = tmp;
转换。所以void*
只是一个要使用的通用临时类型,但是void *tmp
的类型在这里是完全正确的)这样,在验证对
block
的调用成功之前,不会分配重新分配的块。你可以随意增加。加倍就可以了,或者只加一些固定的数字就可以了,等等。。处理重新分配任何东西的计划是直截了当的。您可以分配一个块来容纳一些对象。您保留一个已分配号码的计数器(例如
realloc
)。然后保留一个单独的对象使用数量计数器(比如alloced
)。然后,在为另一个对象使用内存(如果填充循环等)之前,只需检查是否used
,例如:if (used == alloced) { /* check if realloc needed */
/* realloc here */
alloced *= 2; /* update no. allocated (doubling size here) */
}
重新分配并将
used == alloced
计数器更新为新大小,然后继续。。。一个简单的例子是,首先为
alloced
整数分配,然后根据需要重新分配,方法是将当前分配大小加倍以读取和存储无限数量的整数。如前所述,您可以随意增加分配大小,但避免每次添加都重新分配。内存分配是一个相对昂贵的调用。因此,加倍(例如,将2
的存储分配增加到2
的存储分配)是一个合理的增长率,可以避免在添加对象时重复不必要的重新分配。#include <stdio.h>
#include <stdlib.h>
#define MAXI 2 /* initial number of integer to allocate */
int main (void) {
size_t alloced = MAXI, /* counter to track number allocate */
used = 0; /* counter to track number used */
int val = 0, /* value to read from stdin */
*block = malloc (alloced * sizeof *block); /* initial allocation */
if (!block) { /* validate every allocation */
perror ("malloc-block");
return 1;
}
while (scanf ("%d", &val) == 1) { /* while integer read */
if (used == alloced) { /* check if realloc needed */
/* always realloc to a temp pointer, or risk losing pointer */
void *tmp = realloc (block, 2 * alloced * sizeof *block);
if (!tmp) { /* validate every allocation */
perror ("realloc-block");
if (!used) /* if no ints stored, exit */
return 1;
break; /* otherwise original pointer still good */
}
block = tmp; /* assign reallocated block */
alloced *= 2; /* update no. of ints allocated */
}
block[used++] = val; /* add value to block and update used */
}
printf ("no. of bytes allocated : %zu\n"
"no. of bytes used : %zu\n"
"no. of ints stored : %zu\n",
alloced * sizeof *block, used * sizeof *block , used);
free (block); /* don't forget to free what you allocate */
}
示例使用/输出
我们最初分配给
4, 8, 16, 32, 64, 128, ...
,所以让我们尝试阅读2-int
,看看它是如何运行的。。。$ ./bin/malloc_realloc < ../dat/100000int.txt
no. of bytes allocated : 524288
no. of bytes used : 400000
no. of ints stored : 100000
所以你可以看到我们在过去的
100000
中已经被realloc
超额分配了。不错,但由于您知道所使用的整数的数量,您可以最后一次124288-bytes
来调整块的大小,使其正好容纳realloc
,方法是:void *tmp = realloc (block, used * sizeof *block);
...
(这留给您试验——但您不能将
100000-int
设置为小于存储值的大小)内存使用/错误检查
在动态分配内存的任何代码中,对于任何分配的内存块,您都有两个职责:(1)始终保留指向内存块起始地址的指针,以便(2)在不再需要时可以释放它。
必须使用内存错误检查程序,以确保您不会尝试访问内存或写入超出或超出已分配块的界限,尝试读取未初始化值或将条件跳转基于未初始化值,最后确认您释放了已分配的所有内存。
对于Linux
realloc
是正常的选择。每个平台都有类似的内存检查程序。它们都很容易使用,只要运行你的程序就可以了。$ valgrind ./bin/malloc_realloc < ../dat/100000int.txt
==28169== Memcheck, a memory error detector
==28169== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==28169== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==28169== Command: ./bin/malloc_realloc
==28169==
no. of bytes allocated : 524288
no. of bytes used : 400000
no. of ints stored : 100000
==28169==
==28169== HEAP SUMMARY:
==28169== in use at exit: 0 bytes in 0 blocks
==28169== total heap usage: 17 allocs, 17 frees, 1,048,568 bytes allocated
==28169==
==28169== All heap blocks were freed -- no leaks are possible
==28169==
==28169== For counts of detected and suppressed errors, rerun with: -v
==28169== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
(注意:上面分配的
valgrind
字节是1,048,568
的总和)始终确认已释放所有已分配的内存,并且没有内存错误。
再看一遍,如果你还有问题,请告诉我。
如果您想检查总分配的总和,可以从shell(假定是POSIX shell)使用
2 * sizeof(int), 4 * sizeof(int), ....
循环和POSIX数学运算符来完成,例如。sum=0; for i in $(seq 1 17); do sum=$((sum + (1 << i) * 4)); done; echo $sum
1048568
关于c - 如果malloc()仅分配一个只能为一个变量存储的内存块,如何将其用于创建动态数组?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57831125/