谁能帮我解决这个指针问题

can anybody help me to solve this pointer question in c

任何人都可以帮助我理解这段代码(在 c 中)..

#include <stdio.h>

void main()

{

   const int a =5;int b;

   int *p;

   p= (int *) &a;



  b=a;



   *p= *p +1;

   printf(" value of p is = %d\n", *p);  

   printf(" value of b is = %d\n", b);

   printf(" value of a is = %d\n",a);

}

结果是

: p 的值为 = 6

: b 的值为 = 5

:a的值为=6

根据指令 p = (int *)&a;,您使 p 指向 a
结果表达式 *p 引用变量 a,因此 *p = *p + 1; 相当于 a = a + 1; - 变量 a 被分配了它的先前值(即 5 ) 递增 1.
所以终于到了 6.

但是,正如@interjay 在 中指出的那样,这是一个未定义的行为——a 变量被声明为const,这意味着它不能被修改。因此,编译器可能会选择将其分配到只读内存区域。它在你的情况下没有,并且赋值成功,但在其他情况下,变量的修改可能会无声地失败(a 值剩余 5)或产生内存访问异常(并终止程序)或其他任何东西。

在解释之前,让我告诉你,这部分有点问题,并且可能导致未定义的行为:

const int a =5;
p= (int *) &a;

你应该删除const,因为在这种情况下你想通过指针修改a的内容。某些编译器(例如评论中有人提到的 clang)可能会执行优化,例如将使用 const 变量的位置替换为它的值,以减少内存访问操作的次数。


让我们假设每个变量都是一个小盒子,您可以在其中放置数字。所以你有 3 个盒子:

+---+   +---+   +---+
| 5 |   |   |   |   |
+---+   +---+   +---+
  a       b       p

现在让我们检查每个语句,看看发生了什么。

   int *p;

   p= (int *) &a;

p定义为指针,是一种变量,可以保存内存中某物的地址。在这种情况下,它被分配了变量a的地址。所以我们的盒子现在看起来像这样:

  +---------------+
  v               |
+---+   +---+   +----+
| 5 |   |   |   | &a |
+---+   +---+   +----+
  a       b       p

p简单的包含了a的内存地址。你可以用 printf("%u", a) 打印它,你会看到一些数字。即a.

的地址
  b=a;

这里我们将a的值复制到b,所以我们的盒子变成:

  +---------------+
  v               |
+---+   +---+   +----+
| 5 |   | 5 |   | &a |
+---+   +---+   +----+
  a       b       p

   *p= *p +1;

使用 *p 语法,我们可以取消引用指针,这意味着我们可以访问 p 指向的内存(按照箭头)。在这种情况下,*p 将允许我们获取或设置 a 变量的内容。我们的盒子现在变成了这样:

  +---------------+
  v               |
+---+   +---+   +----+
| 6 |   | 5 |   | &a |
+---+   +---+   +----+
  a       b       p

   printf(" value of p is = %d\n", *p);  

在这里你再次取消引用 p,这意味着我们正在获取地址 p 处的内存内容。在我们的例子中,这将获取 a 变量的内容,即 6.

   printf(" value of b is = %d\n", b);

查看 b 框,我们可以看到它包含 5

   printf(" value of a is = %d\n",a);

我们使用指针修改了a。查看 a 框,我们可以看到它包含值 6.

我们逐行进行

const int a =5;int b;

在这一行中,变量b定义为int,变量a定义为const int,这意味着它的值在所有较低的步骤中都是常数,等于5。

int *p;   
p= (int *) &a;

在这两行中,一个名为p的变量被定义为一个指针int,其值(必须是来自内存单元的地址)等于变量a的地址。 这意味着变量 a 和 p 都指向一个公共存储单元。 换句话说:

(*p == a) //IS TRUE. Both are equal to 5

下一行:

  b = a;

即变量b的值也等于a,等于5

*p= *p +1;

这一行中,地址p对应的值增加了一个单位。 我们知道变量 a 和 p 指向一个共同的内存单元。 其实这意味着我们间接给变量a加了一个单位,也就是说两个变量的值都是(5 + 1).

最后,最后三行输出的原因就清楚了

问题完全在下面一行:

p= (int *) &a;

如果没有类型转换,该行将显示为:

p = &a;

a的类型是const intp 的类型是 int *.

很明显,编译器应该警告丢弃 const 限定符:

warning: assigning to 'int *' from 'const int *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]

这说明了为什么您应该始终尝试避免显式类型转换(除非绝对必要)。这段代码的作者搬起石头砸了自己的脚。他们引入了未定义的行为并且隐藏了明显的问题,因为警告被丢弃或抑制

这段代码的目的是通过指针p更新a的值。让我们去掉一些东西,从基础开始:

int a = 5; 
int *p = &a;

我们有一个名为 a 的对象,它存储整数值 5。我们有另一个名为 p 的对象,它存储 a 地址 。在上面的两个声明之后,以下条件为真:

 p == &a  == some address value 
*p ==  a  == 5

表达式 *p 等同于表达式 a - 给 *p 赋新值与赋新值是一样的值为 a,因此

*p = *p + 1

等同于写

a = a + 1

但是,在您发布的代码中 a 已声明为 <em>const</em> int。这意味着您告诉编译器 a 的值在其生命周期内不应改变。编译器将标记任何语句,如

a = a + 1

a++;

作为一个错误。编译器可能也将a存储在只读存储器中;如果您从不获取 a 的地址(也就是说,如果它从来不是一元 & 的操作数),编译器 可能 不会为其保留任何存储空间 at all 并用值替换它的任何实例(IOW,任何你希望在机器代码中看到对 a 的引用的地方你只会看到文字 5), 意味着根本没有什么可写的。

但是这段代码 作弊 - 它声明 p 为指向 non-const int表达式&a的类型是const int *(指向const int的指针),但是p的类型只是int *(指向 int 的指针)。在作业中

p = (int *) &a;

您正在 放弃 a 上的 const 限定符。因此,当您向 *p 写入新值时,编译器 不知道 您正在尝试修改已声明为 const 的内容,因此它赢了' 将其标记为错误。

C 语言定义表明,尝试通过非 const 限定的左值 1 更新 const 限定的对象会导致 未定义的行为 - 编译器不需要以任何特定方式处理这种情况。结果可以是以下任何一项:

  • 运行时错误;
  • a的值保持不变;
  • 表现完全符合预期;

或完全不同的东西。


  1. 左值是指定对象的任何表达式,以便可以读取或修改该对象。 a*p 都是左值,它们引用包含值 5 的整数对象