谁能帮我解决这个指针问题
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 int
。
p
的类型是 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
的值保持不变;
- 表现完全符合预期;
或完全不同的东西。
- 左值是指定对象的任何表达式,以便可以读取或修改该对象。
a
和 *p
都是左值,它们引用包含值 5
的整数对象
任何人都可以帮助我理解这段代码(在 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 int
。
p
的类型是 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
的值保持不变;- 表现完全符合预期;
或完全不同的东西。
- 左值是指定对象的任何表达式,以便可以读取或修改该对象。
a
和*p
都是左值,它们引用包含值5
的整数对象