允许分配什么返回值?

时间:2018-07-07 15:59:10

标签: c malloc language-lawyer

以下哪个函数可能返回1?

分配和释放突然停止工作

int foo1(size_t a) {
    void *t = malloc(a);
    if (t == NULL)
        return 0;
    while (1) {
        free(t);
        t = malloc(a);
        if (t == NULL)
            return 1;
    }
}

无法重新分配但成功分配m

int foo2(size_t a, size_t b) {
    void *t = malloc(a);
    if (realloc(t, b))
        return 0;
    if (malloc(b))
        return 1;
    return 0;
}

既不是新分配也不是纯扩展

int foo3(size_t a, size_t b) {
    void *p, *q;
    p = malloc(a);
    if (malloc(b))
        return 0;
    q = realloc(p, b);
    return p != q && q;
}

1 个答案:

答案 0 :(得分:0)

除了您没有包括<stdlib.h>的事实外,没有令人信服的理由使foo1最终失败并返回1。对于任何给定的a值,此函数的终止是特定于实现的。大多数系统最终将回收释放的块,并且永远不会重新分配a字节,但是free不执行任何操作的系统仍然符合Standard,并且循环最终可能会失败。

函数foo2导致一个或多个内存泄漏。如果1失败,但相同大小的realloc()成功,它将返回malloc()。尽管这种情况令人惊讶,但无法保证无法重新分配块(或者NULL失败了malloc(a))意味着对具有相同大小的malloc()的下一次调用应该失败

函数foo3具有潜在的不确定行为:您不应在p之后使用q = realloc(p, b)的值。如果确实重新分配了该块,则p的值可以成为陷阱值,因此不应将其与任何内容进行比较。您可以通过将p的值存储到unsigned char数组中并在调用realloc之后比较字节值来解决此问题。即使块没有移动,比较也可能会有所不同。似乎没有一种可移植的方法来确定realloc()是否移动了该块。

尽管如此,在p未成为陷阱值的系统上,实际上malloc(b)失败而realloc(p, b)成功并返回另一个地址的可能性很可能:如果内存堆没有对于malloc(b)有一个可用块,malloc将返回NULL,但是如果p之前有可用空间可以合并形成大小为{{1}的块},b可能会成功并返回另一个地址。

所有这些测试都有实现定义的行为。