【问题标题】:malloc and scopemalloc 和范围
【发布时间】:2011-12-27 11:16:07
【问题描述】:

我正在努力用 c 语言处理 malloc - 特别是当它需要 free()'d 时。我在 gcc 中遇到奇怪的错误,例如:

... free(): invalid next size (fast): ...

当我尝试释放 char 指针时。例如,从输入文件中读取时,在执行以下操作时会在某些行崩溃:

FILE *f = fopen(file,"r");
char x[256];
while(1) {
    if(fgets(x,sizeof x,f)==NULL) break;
    char *tmp = some_function_return_char_pointer(x); //OR malloc(nbytes);
    // do some stuff
    free(tmp); // this is where I get the error, but only sometimes
}

我检查了一些明显的东西,例如 x 为 NULL,但它不是;它只是在随机线上崩溃。

但我真正的问题是 - 我什么时候需要使用 free()?或者,可能更正确的是,我什么时候不应该免费使用?如果 malloc 在函数中,我返回使用 malloc() 的 var 怎么办?在 for 或 while 循环中呢? struct 数组的 malloc-ing 是否与 string/char 指针具有相同的规则?

我从 gcc 中程序崩溃时遇到的错误中收集到,我只是不了解 malloc 和 free。我在 Google 上度过了美好的时光,但我仍在碰壁。有没有找到好的资源?我所看到的一切都表明,每当我使用 malloc 时,我都需要使用 free。但后来我尝试了,我的程序崩溃了。所以也许它会根据变量的范围而有所不同?当在循环内部声明变量时,C 是否会在循环结束时释放内存?在函数结束时?

所以:

for(i=0;i<100;i++) char *x=malloc(n); // no need to use free(x)?

但是:

char *x;
for(i=0;i<100;i++) {
    x=malloc(n);
    free(x); //must do this, since scope of x greater than loop?
}

是吗?

希望我是有道理的......

【问题讨论】:

标签: c malloc scope


【解决方案1】:

malloc(n) 从名为 heap 的内存位置分配 n 字节内存,然后返回指向它的 void* 类型的指针。内存是在运行时分配的。动态分配内存后,只要您随身携带指向它的指针(或具体的地址),范围就无关紧要了。例如:

int* allocate_an_integer_array(int n)
{
    int* p = (int*) (malloc(sizeof(int)*n));
    return p;
}

这个函数只是简单地从堆中分配等于 n 个整数的内存,并返回一个指向第一个位置的指针。指针可以根据需要在调用函数中使用。只要指针在你身边,范围就没有关系..

free(p) 将内存返回到堆中。

您唯一需要记住的是释放它,就好像您不释放它并丢失其地址的值一样,就会出现内存泄漏。之所以如此,是因为根据操作系统,您仍在使用内存,因为您还没有释放它,并且会发生内存泄漏..

同样在释放之后,只需将指针的值设置为空,这样你就不会再次使用它,因为相同的内存可能会在任何其他时间再次分配用于不同的目的......

所以,你需要做的就是小心……

希望对你有帮助!

【讨论】:

    【解决方案2】:

    如果你不想要memory leak,你必须从malloc中释放内存。

    这可能非常棘手。例如,如果// do some stuffcontinue,则会跳过free 并导致内存泄漏。这很棘手,所以我们在 C++ 中有 shared_ptr;还有传言说C程序员的薪水比C++程序员高。

    有时我们并不关心内存泄漏。如果内存包含在整个执行生命周期中需要的东西,您可以选择不释放它。示例:环境变量的字符串。

    PS:Valgrind 是一个帮助检测内存错误的工具。对于内存泄漏特别有用。

    【讨论】:

    • 仅仅因为它的生命周期就是执行的全部而忽略释放某些东西是非常糟糕的做法。首先,它会使您的 Valgrind 输出充满错误。
    • 我同意。但我们必须忍受这一点。
    • 如果你是唯一一个写代码的人,你不要使用任何库。现实是你的同事的代码是这样的;并且您依赖的库可能不会释放内存。
    • 如果我的同事在库代码中留下内存泄漏,我会提出请求并让他们修复它...
    • 好吧,你说得有道理。我将说服我的同事为 putenv(strdup(...)) 释放内存。我会努力让他们工作。谢谢。
    【解决方案3】:

    malloc() 是 C 的动态分配器。您必须了解自动(范围)变量和动态(手动)变量之间的区别。

    自动变量在其作用域内有效。他们是你声明的没有任何装饰的人:int x;

    C 程序中的大多数变量应该是自动的,因为它们是某些代码(例如函数或循环)的本地变量,并且它们通过函数调用和返回值进行通信。

    您需要动态分配的唯一时间是当您有一些数据需要超过任何给定范围时。此类数据必须动态分配,并在不再需要时最终释放。

    这方面的主要用法示例是典型的链表。如果您要使用通用的“插入/擦除/查找”列表操作函数,列表节点不可能是任何范围的本地节点。因此,必须动态分配每个节点,并且列表操作函数必须确保它们释放那些不再属于列表的节点。

    总之,变量分配基本上是范围的问题。如果可能的话,保持一切自动化,你不必做任何事情。如有必要,请使用动态分配并注意在适当的时候手动解除分配。

    (编辑: 正如@Oli 所说,有时您可能还希望在严格的本地上下文中使用动态分配,因为大多数平台将自动变量的大小限制为比动态内存的大小。想想“巨大的数组”。超过自动变量的可用空间通常有一个丰富多彩的名称,例如“pile overrun”或类似的东西。)

    【讨论】:

    • +1 建议尽可能避免动态分配。
    • 当您需要一个会破坏堆栈的海量数组(例如一百万个元素)时,动态分配的一个实例是不会超出范围。
    • 你解释它的方式肯定有帮助。来自$x = "some string"; 的PHP,我试图使用malloc 替换分配;将其描述为动态而非自动分配更有意义
    • 关于何时(不)适合mallocate 的精彩解释
    【解决方案4】:

    一般来说,每次调用malloc 都必须有一个对应的调用free* 这与作用域无关(即与函数或循环)。


    * 此规则的例外包括使用strdup 之类的函数,但原理相同。

    【讨论】:

    • 这里需要注意的是,两次调用free(...) 可能会导致崩溃。
    • @xixonia:崩溃是最好的情况,而不是你所期望的。最坏的情况是给攻击者 root。
    • @R..,这一切都让我想回到 C :)
    【解决方案5】:

    当您不再访问它时,您应该释放内存。如果要访问它,则不应释放内存。这会给你带来很大的痛苦。

    【讨论】:

      【解决方案6】:

      广义上讲,malloc() 返回的每个指针最终都必须传递给free()。您存储指针 in 的变量的范围不会影响这一点,因为即使变量不再在范围内,指针指向的内存仍将被分配,直到您调用 @987654323 @就可以了。

      【讨论】:

        【解决方案7】:

        好吧,malloc 内存的范围位于对 mallocfree 的调用之间,或者直到进程停止(即操作系统为进程清理时)。如果您从不致电free,则会发生内存泄漏。当您可以传递给free 的地址在您实际使用它之前超出范围时,可能会发生这种情况 - 这就像丢失汽车的钥匙,汽车仍然在那里,但您不能真正驾驶它。您遇到的错误很可能是因为函数返回了一个指向未使用malloc 分配的内存的指针,或者它返回了一个您传递给free 的空指针,这是您无法做到的。

        【讨论】:

        • 您的意思是“终身”,而不是“范围”。范围适用于标识符,而不是对象。
        • 严格来说,C中的单词是“storage duration”,而不是“lifetime”。 :-)
        • @R..:不,我的意思是“终生”;见 6.2.4 第 2 条。
        • @OliverCharlesworth,哦,打架的话::pops popcorn::
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多