【问题标题】:free allocated memory of array (vs normal var?)释放分配的数组内存(与普通变量相比?)
【发布时间】:2015-12-25 20:19:59
【问题描述】:

我知道,当我们为 var 分配内存时,我们需要通过调用 free() func 并使用指向 var 的指针来释放空间(并且不要让指针悬空)。

但是当我们为 var 数组分配内存时该怎么办? 我们应该去释放数组[0..n]的每个成员,还是仅仅释放第一个成员的指针就足够了?

long *array_p; 
size_t elements_num = 5

array_p = malloc(elements_num*sizeof(long));

选项#1:

free(array_p);
array_p=NULL;

选项#2:

for (i=0; i<array_len-1; ++i)
{
    free(array_p+i);
    array_p+i= NULL;
}

【问题讨论】:

  • 您需要调用free() 的次数与调用malloc() 的次数相同。
  • 你是单独分配元素的吗?如果不是,是什么让你认为你必须单独释放?请提供minimal reproducible example。什么是“var”?
  • malloc() 被调用一次以创建整个数组(我的元素)'array_p =malloc(num_of_elements*element_size)' 我不确定指向该数组的指针是否会释放整个数组,全部或仅第一个元素。

标签: c arrays pointers memory-management


【解决方案1】:

操作系统通常以这种方式工作:每次内存分配都会在内存块中留下痕迹——除了您的实际/真实数据大小(其中包括一些附加信息,例如分配的内存长度、下一个可用内存地址对于即将到来的分配等)。具体来说,

  • 当您分配 40 个字符 的块时,操作系统将分配 56 个字节 — 16 个字节以跟踪分配的内存长度,下一个可用(免费)内存地址等,以及 40 个字节的实际数据。

  • 当你分配一个 40 个整数的块时,这一次,操作系统将分配 176 个字节——同样,16 个字节是为了跟踪分配的内存长度,下一个可用(空闲)内存地址等,以及 (4 × 40 =) 160 字节用于您的实际数据。

因此,当您释放一组数据时,操作系统将已经知道要释放的内存的起始地址和结束地址。

this视频的前20分钟非常详细地解释了该过程。

【讨论】:

    【解决方案2】:

    问题不在于分配数组,而在于分配指针数组。

    对于您使用的每个malloc/calloc,您都需要一个free。现在在这样的情况下

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

    您在内存中有一个连续的 10 个 int 块,您只需要一个 free(array)

    但你可以有一个

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

    现在你有一个包含 10 个int* 的数组,所以指向int。在实际情况下,您的数组无法使用,您必须分配或分配数组的每个元素,例如:

    for (int i = 0; i < 10; ++i)
      arrayOfArray[i] = calloc(5, sizeof(int));
    

    所以第一个数组的每个元素都是一个指针,指向 5 int 的连续内存块。在这种情况下,您有两个级别的分配,实际上您需要两个级别的释放,以相反的顺序,例如:

    for (int i = 0; i < 10; ++i)
      free(arrayOfArray[i]);
    
    free(arrayOfArray);
    

    【讨论】:

    • 谢谢,但它不是指针数组,只是一个普通数组...我将编辑我的问题,以便更清楚
    • 如果它是一个普通数组,您只需要一个空闲空间,操作系统知道指向的内存块的正确大小,因此不需要做额外的工作。
    【解决方案3】:

    但是当我们为 vars 数组分配内存时该怎么办?我们应该吗 去释放数组[0..n]的每个成员,

    是的,你必须free()数组中分配的每个指针。

    或者仅仅释放第一个成员的指针就足够了吗?

    没有。

    例如,

    char *p[50];
    
    for(i = 0; i<50;i++)
    p[i] = malloc(10); 
    
    
    for(i = 0; i<50;i++)
    free(p[i]);
    

    char **p;
    
    p = malloc(50 * sizeof(char*));
    
    for(i = 0; i<50;i++)
    p[i] = malloc(10); 
    
    for(i = 0; i<50;i++)
    free(p[i]);
    
    free(p);
    

    基本上,每次拨打malloc(),您都会拨打一次free()

    【讨论】:

    • 对我来说(尝试)分配 array_p+i= NULL; 意味着 OP 只分配了一个数组。如果他们分配了 n 个块并将地址存储在一个数组中,他们就会知道如何分配array_p[i]
    • 感谢您的快速回答和良好的编辑 :) 我不确定我是否理解您的评论。至于我的(小)知识,指针 p+1...p+n 现在将存储不好的地址(= 悬空指针)。我们不需要更正它吗?
    • @MichalKandel 你的意思是在free()ing 之后给他们分配NULL吗?分配 NULL 不是必需的。这更像是一些人遵循的一种做法。只要您在free()ing 之后不访问这些指针,就可以了。
    【解决方案4】:

    在创建变量数组时,了解所创建的内容很重要。在 C 中,指针的作用类似于数组,因此您需要遍历整个数组,释放每个成员,然后释放第一个成员的指针。简单地将点释放到第一个成员而不释放数组的每个成员通常会导致内存泄漏,这最终可能导致您的程序运行缓慢并最终崩溃或修改/访问您不打算修改的数据(分段错误)。

    【讨论】:

      【解决方案5】:

      你只需将指向第一个元素的指针(这是 malloc 给你的)传递给 free:

      int * array = malloc(10 * sizeof(int));
      ....
      free(array);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-07
        • 2010-09-12
        • 2011-08-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多