这个问题的灵感来自我一直在读的一本C书的截取
哪里是 说:
int num;
int *pi=0; // Zero referes to the null pointer, NULL
pi = #
*pi = 0; // Zero refers to the integer zero
我们习惯了重载运算符,例如使用的星号 声明指针、取消引用指针或乘法。这 零也过载。我们可能会发现这令人不安,因为我们 不习惯重载操作数。
所以我用调试器做了一堆调查,我的答案是调试器向我展示的。这是未定义的行为,我明白了,但我不是在写一个程序,而是在试图弄清楚一些东西。无论如何,每次运行指针时指针都会初始化为 1,我在某些计算中并不依赖于它,而是调试器反复显示的内容。
这实际上只是一个问题,但我必须写更多,否则它不会接受它。 为什么 *p=0 在不同时间有不同的效果?0 如何过载? 如何判断 *p=0 是使 p 成为空指针,还是将 0 分配给 p 指向的变量?编译器如何知道在 p 的地址而不是 p 指向的地址处分配 null?
$ cat prac.c
#include <stdio.h>
int main()
{
int num;
int *p;
printf("0) %p is %dn",p,*p);
*p=0; //Why is this......
printf("1) %p is %dn",p,*p);
num=5;
p=#
printf("2) Now %p is %dn",p,*p);
*p=0; //....different than this
printf("3) p is not null, %p : %dn",p,*p);
return 0;
}
$ ./prac
0) 0x7ffeb36b5c30 is 1 //pointer is initialized to 1, not-null, definitely out-of-bounds though
1) 0x7ffeb36b5c30 is 0
2) Now 0x7ffeb36b5b3c is 5
3) p is not null, 0x7ffeb36b5b3c : 0
您询问的概念是空指针常量。
C 标准将空指针常量定义为
值为
0
的整数常量表达式或此类表达式强制转换 键入void *
所以类型为int
的表达式0
也是一个空指针常量。(请注意,空指针常量不必是指针类型。
该标准进一步指出:
如果将空指针常量转换为指针类型,则 生成的指针(称为空指针)保证可以比较 不等于指向任何对象或函数的指针。
鉴于:
int n;
int *p;
这:
p = 0;
将int
表达式0
隐式转换为类型int*
的空指针,而这:
n = 0;
或
*p = 0;
不执行隐式转换,因为正在初始化的对象已经是int
类型。
何时调用隐式转换的规则在赋值运算符的说明中说明。 相同的规则适用于初始化、参数传递和return
语句。这些规则显式声明将空指针常量转换为目标类型。
请参阅 C11 标准的 N1570 草案(大 PDF)。
空指针- 常量和空指针:6.3.2.3
- 简单分配:6.15.6.1
我不熟悉你引用的书或文章,但它在帮助你理解和使用 C 中的指针方面
失败了。什么是指针?
指针只是一个普通变量,它将其他事物的地址作为其值。换句话说,指针指向可以找到其他内容的地址。在你通常认为一个变量保存一个即时值的地方,例如int a = 5;
,指针将只保存5
存储在内存中的地址,例如int *b = &a;
.无论指针指向哪种类型的对象,它的工作方式都相同。(指针,只是一个指针...
如何声明、分配地址和引用指向的值
让我们以你为例,看看每一行的作用(忽略你的p
和pi
拼写错误,只使用p
):
int num; /* declares an integer 'num' whose value is uninitialized */
int *p = 0; /* declares a pointer 'p' and ininializes the address
* to a the constant expression 0. (a Null Pointer Constant)
*/
请参阅 C11 标准 - 空指针常量 (p3),它是一个值为0
的常量表达式,或转换为类型void *
的此类表达式(例如(void *)0
)。几乎所有的C编译器,如果事实如此,C标准都为此目的提供了NULL
。(参见:C11标准-7.19通用定义)所以你通常会看到:
int *p = NULL; /* declare and initialize 'p' to the Null Pointer Constant */
接下来,一元运算符'&'
用于获取对象的地址。这里:
p = # /* assigns the address of 'num' as the value of 'p', so
* 'p' holds the address of 'num' (e.g. 'p' points to the
* memory location where 'num' is stored).
*/
一元'*'
操作器是取消引用运算符,并提供一种直接访问指针保存(指向)的内存地址处的值的方法,因此:
*p = 0; /* sets the value at the address held by 'p' to zero */
现在让我们看一下您的代码和输出:
int num;
int *p;
printf("0) %p is %dn",p,*p);
p
持有的地址是什么,num
的价值是什么?
您试图访问未初始化的指针和未初始化的整数的值。您刚刚调用了未定义的行为。代码的定义操作已经结束,任何事情都可能发生,从看起来行为正常或SegFault'ing。您不能访问未初始化的值。
*p=0;
printf("1) %p is %dn",p,*p);
p
现在初始化为Null 指针常量,则无法再次取消引用 NULL 指针 -- 未定义的行为。
num=5;
p=#
printf("2) Now %p is %dn",p,*p);
哈利路亚!num
现在初始化为5
并且p
现在持有(指向)有效的内存地址!(但不幸的是,一旦你调用了未定义的行为,游戏就结束了,你可能会也可能不会得到正确的输出,但幸运的是你看起来是。
*p=0;
printf("3) p is not null, %p : %dn",p,*p);
p
指向什么?(提示:num
)。取消引用运算符有什么作用?(提示:允许您访问指针保存的内存位置的值)。那么*p = 0;
做了什么呢?(提示:你只需将num
的值设置为0
,也就是p
持有的地址处的值)
如果您有其他问题,请告诉我。