[英]How to use or free dynamically allocated memory when I run the program multiple times?
如何释放动态分配的内存?
假设输入(假设它是由用户给定的)是1000,现在如果我分配了1000的内存,并且在此之后(第二次)如果用户给出的输入是500,我可以重用已经分配的内存吗?
如果用户现在输入值说3000,我该如何处理? 我可以重用已经分配的1000个内存块,然后再创建2000个内存块吗? 还是应该创建所有3000个内存块?
哪些是明智的?
#include <stdio.h>
#include <stdlib.h>
typedef struct a
{
int a;
int b;
}aa;
aa* ptr=NULL;
int main() {
//code
int input=2;
ptr=malloc(sizeof(aa)*input);
for(int i=0;i<input;i++)
{
ptr[i].a=10;
ptr[i].b=20;
}
for(int i=0;i<input;i++)
{
printf("%d %d\n",ptr[i].a,ptr[i].b);
}
return 0;
}
我相信,您需要阅读有关分配内存的“生命周期” 。
对于诸如malloc()
和family之类的分配器函数malloc()
对于“内存管理函数”,从C11
第7.27.2章引用)
[...]分配对象的生存期从分配一直到释放为止。 [....]
因此,分配后,指向内存的返回指针将保持有效,直到被释放。 有两种方法可以释放它
free()
的调用 因此,从分配点到程序终止或free()
调用(以较早者为准free()
,分配的内存都是可用的。
就目前而言,我要澄清两个方面。
方案1:
You allocate memory (size M) You use the memory You want the allocated memory to be re-sized (expanded/ shrinked) You use some more You're done using
如果这是您期望的流程,则可以使用realloc()
调整分配的内存大小。 完成后,使用free()
。
方案2:
You allocate memory (size M) You use the memory You're done using
如果是这种情况,请在完成后使用free()
。
注意:在这两种情况下,如果程序多次运行,则在每个单独的调用中发生的分配之间或之间没有连接。 他们是独立的。
当您使用动态分配的内存并调整其大小时,重要的是要准确跟踪已为其分配了多少个元素。
我个人喜欢将使用中的元素数保留在名为used
变量中,而我为size
分配的内存数也要保留。 例如,我可能会创建一个用于描述一维双精度数组的结构:
typedef struct {
size_t size; /* Number of doubles allocated for */
size_t used; /* Number of doubles in use */
double *data; /* Dynamically allocated array */
} double_array;
#define DOUBLE_ARRAY_INIT { 0, 0, NULL }
我想将动态分配的内存指针显式初始化为NULL
,并将它们各自的大小初始化为零,因此我只需要使用realloc()
。 这行得通,因为realloc(NULL, size)
完全等同于malloc(NULL)
。 我还经常利用以下事实: free(NULL)
是安全的,什么也不做。
我可能会写几个辅助函数。 也许可以确保数组中at_least
条目有空间的函数:
void double_array_resize(double_array *ref, size_t at_least)
{
if (ref->size < at_least) {
void *temp;
temp = realloc(ref->data, at_least * sizeof ref->data[0]);
if (!temp) {
fprintf(stderr, "double_array_resize(): Out of memory (%zu doubles).\n", at_least);
exit(EXIT_FAILURE);
}
ref->data = temp;
ref->size = at_least;
}
/* We could also shrink the array if
at_least < ref->size, but usually
this is not needed/useful/desirable. */
}
我肯定会编写一个帮助程序函数,该函数不仅释放所使用的内存,而且还更新字段以反映该情况,以便在释放之后调用double_array_resize()
是完全安全的:
void double_array_free(double_array *ref)
{
if (ref) {
free(ref->data);
ref->size = 0;
ref->used = 0;
ref->data = NULL;
}
}
程序可能会使用上面的方法。
int main(void)
{
double_array stuff = DOUBLE_ARRAY_INIT;
/* ... Code and variables omitted ... */
if (some_condition) {
double_array_resize(&stuff, 321);
/* stuff.data[0] through stuff.data[320]
are now accessible (dynamically allocated) */
}
/* ... Code and variables omitted ... */
if (weird_condition) {
/* For some reason, we want to discard the
possibly dynamically allocated buffer */
double_array_free(&stuff);
}
/* ... Code and variables omitted ... */
if (other_condition) {
double_array_resize(&stuff, 48361242);
/* stuff.data[0] through stuff.data[48361241]
are now accessible. */
}
double_array_free(&stuff);
return EXIT_SUCCESS;
}
如果我想将double_array
用作堆栈,则可以这样做
void double_array_clear(double_array *ref)
{
if (ref)
ref->used = 0;
}
void double_array_push(double_array *ref, const double val)
{
if (ref->used >= ref->size) {
/* Allocate, say, room for 100 more! */
double_array_resize(ref, ref->used + 100);
}
ref->data[ref->used++] = val;
}
double double_array_pop(double_array *ref, const double errorval)
{
if (ref->used > 0)
return ref->data[--ref->used];
else
return errorval; /* Stack was empty! */
}
每当数组空间不足时,上面的double_array_push()
再分配100个双打。 但是,如果您推动了数百万的双打,这将意味着数以万计的realloc()
调用,这通常被认为是浪费的。 取而代之的是,我们通常采用重新分配策略 ,该策略将大小与现有大小成比例地增长。
我的首选策略是类似(伪代码)的东西
If (elements in use) < LIMIT_1 Then
Resize to LIMIT_1
Else If (elements in use) < LIMIT_2 Then
Resize to (elements in use) * FACTOR
Else
Resize to (elements in use) + LIMIT_2
End If
LIMIT_1
通常是一个很小的数字,是分配的最小大小。 LIMIT_2
通常是一个很大的数字, LIMIT_2
为2 20 (两百万加零钱),因此最多可以分配LIMIT_2
未使用的元素。 FACTOR
介于1和2之间; 许多建议2
,但我更喜欢3/2
。
该策略的目标是将realloc()
调用的数量保持在可接受(不引起注意)的水平,同时使分配但未使用的内存量保持较低。
最后要注意的是,如果您出于相同(或非常相似)的目的重用它,则应仅尝试保留动态分配的缓冲区。 如果您需要不同类型的数组,并且不需要较早的数组,则只需free()
较早的数组,然后malloc()
新建一个数组(或让助手中的realloc()
做到这一点)。 无论如何,C库将尝试重用相同的内存。
在当前的台式机上,与该程序的启动时间相比,大约一百或一千个malloc()
或realloc()
调用可能不太明显。 因此,最小化这些呼叫的数量并不是很重要。 您要做的是使代码易于维护和调整,因此逻辑重用以及变量和类型名称很重要。
重用缓冲区的最典型情况是逐行读取文本输入。 我使用POSIX.1 getline()
函数来这样做:
char *line = NULL;
size_t size = 0;
ssize_t len; /* Not 'used' in this particular case! :) */
while (1) {
len = getline(&line, &size, stdin);
if (len < 1)
break;
/* Have 'len' chars in 'line'; may contain '\0'! */
}
if (ferror(stdin)) {
fprintf(stderr, "Error reading standard input!\n");
exit(EXIT_FAILURE);
}
/* Since the line buffer is no longer needed, free it. */
free(line);
line = NULL;
size = 0;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.