C语言 为什么指针在声明后初始化和取消引用时给出垃圾/随机值?



代码片段-1

int x=3;   
int *p=&x; 
printf("x= %dn",x);
printf("p= %dn",*p);

代码片段-2

int x;
int *p;
x=3;
*p=&x;
printf("x= %dn",x);
printf("p= %dn",*p);

片段-1 给出输出 x=3 和 p=3,但片段 2 给出 x=3 和 p=某个随机值

请解释一下

这一行:

int *p=&x;

是具有初始化的p声明。 它将p初始化为&x,这是一个int *

相比之下,这一行:

*p=&x;

是一项作业。 它首先取消引用p,然后将&x分配给取消引用的对象。 这是错误的,原因有二:

  • p不会指向任何地方,因此尝试取消引用它会调用未定义的行为。
  • 即使p确实指向某个地方,您也会尝试将int *分配给int

此代码片段具有未定义的行为

int x;
int *p;
x=3;
*p=&x;
printf("x= %dn",x);
printf("p= %dn",*p);

因为指针p未初始化,并且具有不确定的值,该值不指向有效对象。所以这个说法

*p=&x;

通过取消引用指针(*p(试图访问无效地址的内存。

似乎相反,这句话

*p=&x;

你是说

p = &x;

即指针获取变量x的地址。

注意这种 printf 调用的输出消息

printf("p= %dn",*p);

令人困惑。最好写

printf("*p= %dn",*p);

也就是说,输出的不是指针本身的值,而是输出的指向对象的值。

您应该在声明和表达式中区分星号的含义。

在这样的声明中

int *p=&x; 

星号表示此处声明为指针,它获取变量 x 的地址。

在这样的表达式语句中

*p=&x;

星号表示取消引用运算符,该运算符用于通过存储在用作地址的指针中的值来访问指向的对象。

int *p=&x;等效于

int *p;
p = &x; // <== p, not *p

p = &x获取变量 x 的地址,并将其放在p中(这是一个指针(。

这与您在片段 2 中执行的操作不同

*p = &x; // Not the same

*p = &x获取变量 x 的地址,并将其放置在p指向的位置。因此,p仍然指向同一位置,但该位置写入了不同的值。(并且由于p没有初始化,它不会指向任何有用的东西,从而导致未定义的行为(

int *p = &x;

(在第一个片段内(

不同于

int *p;
*p = &x;

(在第二个片段内(

在第一种情况下,您通过x的地址初始化p

在第二种情况下,在第二个语句中使用*p时,您取消引用p它指向没有有效对象,并尝试将x的地址分配给p应指向的不存在的对象,这将调用未定义的行为。

通常,这应该至少在编译时给您一个警告。如果未显示,请引发编译器警告。

声明处的*用于指示指针。

声明后的*用于取消引用指针。


如果您希望代码段 2 正常运行,则需要在分配中省略*

int x;
int *p;
x = 3;
p = &x;            // No * operator here.
printf("x = %dn", x);
printf("*p = %dn", *p);

最新更新