在 C 中为指针赋值时如何'overloaded'零



这个问题的灵感来自我一直在读的一本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=&num;
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;.无论指针指向哪种类型的对象,它的工作方式都相同。(指针,只是一个指针...

如何声明、分配地址和引用指向的值

让我们以你为例,看看每一行的作用(忽略你的ppi拼写错误,只使用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 = &num;   /* 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=&num;
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持有的地址处的值)

如果您有其他问题,请告诉我。

最新更新