取消引用和将变量的地址分配给 C 中的指针变量有什么区别?

What is the difference between derefencing and assigning the address of a variable to pointer variable in C?

看下面两个代码!

int main() {
    int a = 12;
    int *p;
    *p = a;
}

和这段代码,

int main() {
    int a = 12;
    int *p;
    p = &a;
}

在第一段代码中将指针解引用为this *p = a,在第二段代码中,变量a的地址被设置为指针变量。

我的问题是这两段代码有什么区别?

在你的第一段代码中:

int main() {
    int a = 12;
    int *p;
    *p = a;
}

你有一个严重的 未定义行为 的情况,因为你试图做的是将 a 的值分配给 int 变量p 目前指向。但是,p 尚未分配 'address',因此它将具有任意 - 和 invalid - 值! 一些 编译器可能会将 p 初始化为零(或 NULL),但这仍然是一个无效地址(在 大多数 系统上).

您的第二个代码片段是 'sound',但就目前而言,实际上 没有实现任何目标:

int main() {
    int a = 12;
    int *p;
    p = &a;
}

在这里,您正在为您的指针变量 p 分配一个值(即 地址 );在这种情况下,p 现在 指向 a 变量(也就是说,它的值是 地址 a).

因此,如果您将这样的代码附加到(到第二个代码段的末尾):

*p = 42;

然后打印出a的值,你会看到它的值已经从最初给定的12变成了42.

随时要求进一步澄清and/or解释。

第一个不好:

int main() {
    int a = 12;
    int *p;
    *p = a;
}

表示:将变量a的值放入指针p指向的位置。但是 p 点是什么?可能什么都没有(NULL)或任何随机地址。在最好的情况下,它可能会导致执行错误,例如访问冲突或分段错误。在最坏的情况下,它可能会覆盖完全未知变量的任何现有值,从而导致难以调查的问题。

第二个可以。

int main() {
    int a = 12;
    int *p;
    p = &a;
}

意思是:获取指向(现有)变量a的指针并将其赋值给指针p。所以,这可以正常工作。

当你初始化一个指针时,你可以使用 *p 来访问指向变量的指针的值,而不是指向变量的地址,但是不可能像那样影响值(*p=a) .因为你试图影响一个没有变量地址的值。

第二个代码正确使用 p = &a

声明 *pa 在内存中保留一些 space,第一种情况下是指针,第二种情况下 a 是什么(int).

在这两种情况下,如果您不在其中放置任何内容,它们的值将不会被初始化。这并不意味着里面没有 nothing,因为那是不可能的。这意味着它们的值尚未确定,有点像 "random" ;加载程序在请求时只是将 code/data 放入内存中,而 p 占用的 space 和 a 占用的 a 都是当时内存中的任何内容加载(也可能在编译时,但无论如何,未确定)。

因此,在第 1st 种情况下,您在执行 *p = a 时冒了很大的风险,因为您要求处理器将字节 "inside" a 并将它们存储在 p 指向的任何地方。可能在数据段的范围内,在堆栈中,某处它不会导致 立即 problem/crash,但很有可能 非常 可能不行!

这就是为什么这个问题据说会导致 "Undefined Behavior" (UB)。

What is the difference between dereferencing and assigning the address of a variable to pointer variable in C?

后者是前者的前提。它们是实现指针取消引用的好处的独立步骤。


为了解释它们之间的区别在哪里,我们必须分别看看这些家伙是什么:


  • 什么是取消引用指针?

首先我们需要看看什么是引用。引用是 f.e。对象的标识符。我们可以说 "Variable a stands for the value of 12." - 因此,a 是对 12.

值的引用

对象的标识符是对存储在其中的值的引用。

指针也是如此。指针就像普通的对象一样,它们在内部存储一个值,因此它们引用其中存储的值。

"Dereferencing"是当我们"disable"这个连接到通常的值内并且使用p的标识符到access/refer到一个不同于存储的值的值p.

"Dereferencing a pointer" 的意思很简单,您使用指针访问存储在另一个对象 f.e 中的值。 12 in a 而不是通过它自己的标识符 a.

要取消引用指针,* 取消引用运算符需要在指针变量之前,如 *p.


  • 什么是将变量的地址分配给指针?

我们正在实现 "What is dereferencing a pointer?" 中所述的事情,方法是为指针提供另一个对象的地址作为其值,类似于我们为普通变量赋值。

但是与通常的对象 initializations/assignments 不同,为此我们需要使用 & 符号运算符,在变量之前,指针指向的值和 *必须省略指针之前的取消引用运算符,例如:

  p = &a;

之后,指针 "points" 指向存储所需值的地址。


正确取消引用指针的步骤:

首先要做的是声明一个指针,如:

 int *p;

在本例中,我们声明了一个p的指针变量,它指向一个int.

类型的对象

第二步是用int类型对象的地址值初始化指针:

 int a = 12;
 p = &a;       //Here we assign the address of `a` to p, not the value of 12.

注意:如果你想要一个对象的地址值,就像一个普通的变量,你需要在对象之前使用&的一元运算符。


如果您完成了这些步骤,您最终可以通过使用 * 运算符访问指针指向的对象的值,在指针对象之前:

     *p = a;

My question is what is the difference between both pieces of codes?

区别就这么简单,第一段代码:

int main() {
    int a = 12;
    int *p;
    *p = a;
}

对于通过取消引用指针来寻址对象无效。如果在指针确实引用之前没有进行引用,则不能为指针的取消引用赋值。

因此,您的假设:

In the first piece of code I dereferenced the pointer as this *p = a...

不正确。

在这种情况下,您根本无法使用 *p = a 以正确的方式解除对指针的引用,因为指针 p 没有任何引用,您将能够正确取消对指针的引用。

事实上,你正在将 a 的值与 *p = a 的语句赋值到你记忆中的涅盘中。

通常,编译器应该 永远不会在没有错误的情况下通过它。

如果他这样做了,而你稍后想使用你认为你通过使用指针正确分配的值,比如 printf("%d",*p) 你应该得到一个 Segmentation fault (core dumped).