我无法减小动态创建的数组的大小。这是我的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错误。为什么呢?
我想我错过了一些简单的事情,因为我已经看到很多与realloc
缩小记忆相关的问题,但他们都认为这是可能的。
我使用Ubuntu 14.04和GCC 4.8.2并使用-std=c99
选项进行编译。
答案 0 :(得分:8)
b[8]
调用中的 printf
访问未分配的内存并调用未定义的行为。这就是基本上未定义的行为意味着什么。结果是不可预测的。它看起来似乎工作正常,但下次可能会崩溃。这里还有其他一些事情需要考虑 -
malloc
无法分配内存,因此使用assert
宏检查其返回值是错误的。应该使用assert
来调试不可能或错误的代码,例如从数据库中访问数组。
您不应该投射malloc
的结果。 Do I cast the result of malloc?
realloc
可能无法重新分配像malloc
这样的内存块。当它失败时,它返回NULL
并保持旧块不变。这意味着您将丢失旧内存块上的句柄,导致其泄漏。在调用realloc
之前,您应该将指针存储在变量中的旧块中。
答案 1 :(得分:5)
您正在访问未分配的空间。这是未定义的行为。在最坏的情况下,像现在一样,它仍然有效。 Segfault不保证会发生。
答案 2 :(得分:1)
Realloc将标记剩余的缓冲区,以供将来的malloc操作使用。它是UB,如果在该缓冲区上没有发生malloc,你仍然可以访问该缓冲区,这就是你的情况。你很幸运没有获得访问未分配内存的段错误。
答案 3 :(得分:1)
未定义,当您执行此操作时,它可能会崩溃,具体取决于您访问的内存是否属于您的进程:
int i;
int a[5];
for(i=0;i<10;i++)
printf("%d\n", a[i]);
你必须亲自检查一下。