有人可以向我解释为什么*x
始终返回0
而*(x + 1)
返回诸如-805306368
,536870912
之类的值吗?
int * x = malloc(sizeof(int) * 2);
printf("%d, %d\n", *x, *(x + 1));
我正在使用gcc
,但是在clang
中也遇到了相同的行为。
我的理解是malloc
将在堆上为两个int
值分配足够的内存。我假设*x
将引用第一个未初始化的int
,而*(x + 1)
将引用第二个未初始化的int
。
我不认为这是this的副本,因为*x
总是 0
。我对*(x + 1)
为什么返回“垃圾”有一个不错的了解,但是对于*x
如此0
如此稳定的原因却知之甚少。
答案 0 :(得分:2)
*x
等效于*(x + 0)
,*(x + n)
等效于x[n]
,其中x
是指针,n
是整数。因此,您要打印x[0]
和x[1]
-整数数组的第一和第二个元素。
用malloc
分配的对象的字节是不确定的,除非已初始化,因此对象的值也是如此。该标准说(C11 3.19.2-3.9.4; same text in C17 but cannot link it as nicely):
确定价值
未指定值或陷阱表示
和
未指定值
在任何情况下本国际标准均不要求选择哪种值的相关类型的有效值
注意。未指定的值不能是陷阱表示。
和
陷阱表示
不需要表示对象类型值的对象表示形式
int
对象在GCC中不能包含陷阱表示。但是,该行为仍然没有得到很好的说明,因为该标准并未对在任何实例中选择哪个值强加要求-甚至
printf("%d, %d\n", x[0], x[0]);
可以打印
0, 42
因此“检查”不确定值是没有意义的。
“假设规则”允许编译器完全取消对malloc
的调用-这样,即使malloc
实现始终将前4个字节清零的块,也可以将编译后的代码x[0]
的号码有任何变化。
答案 1 :(得分:0)
我假设* x将引用第一个未初始化的int,而*(x + 1)将引用第二个未初始化的int。
您的假设是正确的。但是正如您自己说的那样:您正在取消引用具有不确定值的未初始化数据的指针。但是,仅从数据来看,就无法确定其是否已初始化。
要初始化内存,请使用calloc()
:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int *x = calloc(2, sizeof *x);
printf("%d, %d\n", x[0], x[1]);
}
我最终希望使用一种方法来遍历固定大小的数组,并仅显示已初始化的值。我不确定如何做到这一点。
使用第二个数组来跟踪分配:
#include <assert.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
enum { LENGTH = 4 };
int main(void)
{
int *data = calloc(LENGTH, sizeof *data);
bool *initialized = calloc(LENGTH, sizeof *initialized);
data[1] = 0;
initialized[1] = true;
data[3] = 42;
initialized[3] = true;
for (size_t i = 0; i < LENGTH; ++i)
if (initialized[i])
printf("%zu: %d\n", i + 1, data[i]);
}