假设我们在C中具有以下声明:
double d[25], * p;
int * t;
char * c;
我们如何解释以下printf()结果?
printf("d : %x\t",d);
printf("p : %x\t",p);
printf("t : %x\t",t);
printf("c : %x\t",c);
其中将打印ligne:
d : 62fd30 p : 1 t : 0 c : 39
我们可以很清楚地看到d的内存地址,但是p,t和c看起来都不像地址。我曾经认为,未初始化的指针在声明后采用Null值。我错了吗?我们如何解释这些结果?
答案 0 :(得分:5)
所有自动(非静态局部)变量将使用 indeterminate 值(可能看起来是随机的或垃圾的)未初始化。变量是否是指针都没有关系。
此外,仅读取未初始化指针的值并不会自动UB(在C中),但是取消引用绝对会是未初始化指针。
但是,正如一个评论中所述,您需要使用"%p"
来打印指针(从技术上讲,它们也必须转换为void *
)。 printf
格式说明符和参数类型 do 不匹配会导致UB。
答案 1 :(得分:3)
您不能假定声明后任何指针都将被零初始化-C标准此时不暗示任何内容。其他类型的值也是如此。这就是为什么在声明时设置变量值的一种好习惯,例如:
int * t = NULL;
某些编译器会对变量进行零初始化,但这是特定于工具的功能。
答案 2 :(得分:3)
我以前认为未初始化的指针使用空 声明后的值。我错了吗?
是,您的假设不正确。用自动存储声明的未初始化指针始终包含垃圾数据或垃圾数据,即不是有效地址,因此最好在声明时首先使用NULL
进行初始化。对于例如
double *d = NULL;
/* some processing */
if(d == NULL) {
/* @TODO error handling. Not allowed to de-reference NULL pointer */
}
这里
double d[25];
printf("d : %x\t",d);
d
是25
的double数组和数组名称本身的地址的数组,而使用d
打印%x
会导致不确定的行为,即使您的编译器也可能已经警告过您
main.c:5:19:警告:格式指定了类型'unsigned int',但是 参数的类型为'double *'[-Wformat]
但是您似乎忽略了编译器警告,一个不应该。始终使用最少的标志,例如-Wall
来编译代码。例如
gcc -Wall -Werror -Wpedantic test.c
要打印阵列名称,请使用%p
格式说明符。例如
double d[25];
printf("Array d : %p\t",(void*)d);
与int
指针t
和char
指针c
相似,使用%p
格式说明符代替%x
。另外,请勿在代码中保留任何未初始化的指针。
int * t; /* initialized with valid address else
dereferencing uninitialized pointer causes UB */
printf("t : %p\n",(void*)t);