0

我无法减小动态创建的数组的大小。这是我的main函数的样子:

int main(void) {
    // Intialize big array
    int * a = (int *)malloc(10*sizeof(int));
    assert(a);
    // Fill it with squares
    for (int i = 0; i < 10; ++i)
        a[i] = i*i;
    // Expected to print 64
    printf("%d\n", a[8]);
    // Shrink the big array
    int * b = (int *)realloc(a, 5*sizeof(int));
    assert(b);
    // Expected to cause SEGFAULT
    printf("%d\n", b[8]);
    return 0;
}

一切正常,除了printf("%d\n", b[8]);行,因为它打印64,但没有像我预期的那样导致 SEGFAULT 错误。为什么?

我想我错过了一些简单的东西,因为我已经看到了很多与缩小内存有关的 SO 问题realloc,但他们都说这是可能的。

我正在使用带有 GCC 4.8.2 的 Ubuntu 14.04 并使用-std=c99选项编译它。

4

4 回答 4

8

b[8]在第二次printf调用中访问未分配的内存并调用未定义的行为。这就是基本未定义行为的含义。结果是不可预测的。它可能看起来工作正常,但下一次它可能会崩溃。这里几乎没有其他需要考虑的事情 -

  • malloc可能无法分配内存,因此使用assert宏检查其返回值是错误的。assert应该用于调试不可能或错误的代码,例如访问超出范围的数组。

  • 您不应该转换malloc. 我要转换 malloc 的结果吗?

  • realloc可能无法重新分配像malloc. 当它失败时,它会返回NULL并保持旧块不变。这意味着您将失去对旧内存块的处理,从而导致它泄漏。您应该在调用之前将指向旧块的指针存储在一个变量中realloc

于 2014-05-14T06:36:19.893 回答
5

您正在访问未分配的空间。那是未定义的行为。在最坏的情况下,就像现在一样,它仍然有效。不保证会发生段错误。

于 2014-05-14T06:32:01.443 回答
1

Realloc 只会标记剩余的缓冲区可用于未来的 malloc 操作。它是 UB,如果该缓冲区上没有发生 malloc,您仍然可以访问该缓冲区,这就是您的情况。您很幸运没有在访问未分配的内存时遇到段错误。

于 2014-05-14T06:35:46.210 回答
1

它是未定义的,当你跟随它时它可能会崩溃,这取决于你正在访问的内存是否属于你的进程:

int i;
int a[5];
for(i=0;i<10;i++)
  printf("%d\n", a[i]);

你必须自己检查。

于 2014-05-14T06:36:08.570 回答