【问题标题】:Repeatedly allocate memory without freeing it重复分配内存而不释放它
【发布时间】:2019-01-07 09:16:36
【问题描述】:

下面的代码显示了一个重复分配内存而不首先调用free 的示例。相反,它在循环之后释放**sign

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

float ** fun(int nloc)
{
    float **sign;
    int i,nt=100,it,k;
    sign=(float **)calloc(nloc,sizeof(float *));
    for (i=0;i<nloc;i++)
        sign[i] = (float *)calloc(nt,sizeof(float *));

    for (it=0;it<nt;it++){
        for (k=0;k<nloc;k++){
            sign[k][it]=it*0.2;
        }
    }
    return sign;
}


int main(int argc, char *argv[])
{
    int i,isrc,n=3,nloc=1;
    float **sign=NULL;
    for (isrc=0;isrc<n;isrc++){
        sign = fun(nloc);
    }
    for (i=0;i<nloc;i++){
        free(sign[i]);
    }
    free(sign);
    exit(0);
}

这是一个正确的代码 sn-p。我的问题是:为什么我们可以在每次迭代中为指针分配内存而不必先释放它是合法的?

[补充信息]:

大家好,我认为有一种情况我们不能在循环中使用free 内存。如果buffer=pp 在循环外定义,比如:

float *buffer, *p;
/* Elements of p calculated */
for (...){
    /* allocate memory for **buffer */    
    buffer = p;
    free(buffer)
    /* if free here will cause p lost */
}

如果在每个循环结束时释放buffer,可能会导致p丢失,因为bufferp共享相同的内存地址。

【问题讨论】:

  • 你明白signsign[0], sign[1], etc.的区别吗?
  • 他们不是nloc不同的指针吗?
  • 代码存在内存泄漏(也就是说,它调用calloc 的次数比它调用free 的次数多)。编译器不会就此向您发出警告,因为编译器很难(如果不是不可能的话)检测到此类问题。但是,有一些工具(例如 valgrind在运行时检测内存泄漏。
  • 一个原因:有时您希望能够分配更多内存而无需先释放先前的内存(例如,如果您正在构建一个链表,您不希望编译器强制你释放列表中的第一个节点,只是因为你现在继续创建列表中的第二个节点)
  • 当调用任何堆分配函数malloc calloc realloc, 1) 始终检查 (!=NULL) 返回值以确保操作成功。 2)返回的类型是void*,可以分配给任何指针。强制转换只会使代码混乱,使其更难以理解、调试等

标签: c pointers function-pointers free dynamic-memory-allocation


【解决方案1】:

为什么我们可以在每次迭代中为指针分配内存而不必先释放它是合法的?

释放动态分配的内存的责任留给了程序员。这是合法的,因为编译器不会强制执行它,尽管有代码检查工具可以标记这个问题。

释放动态分配的内存应该按照分配的相反顺序进行。例如:

for (i=0;i<nloc;i++)
    free(sign[i]);

free(sign);

【讨论】:

  • 嗨桑迪,我发现了一个例外。请您看一下我的[补充信息]并为此做一些cmets吗?谢谢。
【解决方案2】:

这是合法的,因为在 C 中,您作为程序员负责内存管理。这是有充分理由的。引用another thread

垃圾收集需要用于跟踪分配的数据结构 和/或引用计数。这些会在内存中产生开销, 性能和语言的复杂性。 C++ 被设计为 “贴近金属”,也就是说,它需要更高的性能 权衡与便利功能的一面。其他语言使 这种权衡不同。这是考虑的因素之一 选择您喜欢的语言。

不仅性能和代码大小是一个考虑因素,而且不同的系统对内存有不同的寻址方案。也正是因为这个原因,C 语言很容易跨平台移植和维护,因为没有垃圾收集可以改变。

编辑:一些答案提到释放内存空间而不是指针本身,值得进一步说明这意味着什么:free() 只是将分配的空间标记为可用,它不是“释放”或擦除的,也没有任何其他操作发生在该内存空间上。然后程序员仍然有责任删除分配给指针变量的地址。

【讨论】:

  • 我发现了一个异常。请您看一下我的[补充信息]并为此做一些cmets吗?谢谢。
  • 嗨@coco 我似乎看不到你的消息。如果您需要帮助,很乐意提供更多信息。
【解决方案3】:

我的问题是:为什么我们可以在每次迭代中为指针分配内存而不必先释放它是合法的?

简答

C 牺牲安全性来获得简单性和性能。

更长的答案

你没有释放 指针。你释放了指针指向的内存块。

想想malloc(和calloc)做了什么。它们都分配一块内存,如果分配成功,它们会返回一个指向该内存块的指针。分配函数(像所有函数一样)没有洞察力,也无法控制您对返回值所做的任何事情。这些函数甚至看不到您分配返回值的指针。

实现对它的保护会相当复杂(相对而言,C 的结构非常简单)。首先,考虑这段代码:

int * a = malloc(1);
int * b = a;
a = malloc(1);
free(b);
free(a);

此代码没有内存泄漏,即使我们做了您所要求的精确操作。在从第一个 malloc 调用内存之前,我们重新分配了 a。它工作正常,因为我们已经将地址保存在b

因此,为了禁止重新分配指向内存块的指针没有其他指针指向,运行时环境需要跟踪这一点,这并非完全无关紧要。它还需要创建额外的代码来处理所有这些。由于此检查需要在运行时进行,因此可能会影响性能。

另外,请记住,尽管 C 在今天看起来非常低级,但它在出现时被认为是高级语言。

【讨论】:

  • 我发现了一个异常。你能看看我的[补充信息]并对此做一些cmet吗?谢谢。
  • @coco 你不能两次释放同一个分配。
猜你喜欢
  • 1970-01-01
  • 2014-04-02
  • 1970-01-01
  • 2011-12-09
  • 1970-01-01
  • 2011-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多