代码片段-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);