在将地址 int "i" 分配给指针 "p" 时,"p = &i" 和“*p = i”之间有什么区别吗
Is there any differences between "p = &i" and "*p = i" while assigning the address int "i" to a pointer "p"
我在我的C编程书上找到了这段代码:
int i = 42;
int *p;
p = &i; // & is address of sign
*p = i; // * is dereference sign
"p = &i"和"*p = i"有区别吗??
"p"使用这两个表达式会不会有不同的特点???
编辑:因为这段代码只是试图解释指针的概念,所以它不可运行...所以这两个赋值的顺序在这种情况下不相关...抱歉让事情变得模糊。 ..
Is there any differences between “p = &i” and “*p = i” while assigning the address int “i” to a pointer “p”
是的,有很大的不同。只有 p = &i
表示 "assign the address of i
to p
".
另一方面 *p = i
表示 "assign the value of i
to the value at the address that is stored in p
"。你可以通过一个简单的例子看到结果:
int i = 42;
int* p;
p = &i;
printf("%d", i);
*p = 5;
printf("%d", i);
int j = 3;
printf("%d %d", i, j);
p = &j;
*p = i;
printf("%d %d", i, j);
首先,快速总结 - 给定声明
int i, *p;
和声明
p = &i;
则下列说法成立:
p == &i // int * == int *
*p == i // int == int
您已将 i
的 地址 分配给 p
。因此,表达式 *p
和 i
的计算结果相同。给*p
赋值和给i
赋值是一样的,从*p
读一个值和从i
读一个值是一样的。如果你后来做了类似
的事情
*p = 10;
那么这就和写一样了
i = 10;
IOW,您正在为 p
指向 的事物分配一个新值。
如果我们引入多级间接寻址,例如:
int i;
int *p = &i;
int **q = &p;
则下列皆为真:
q == &p // int ** == int **
*q == p == &i // int * == int * == int *
**q == *p == i // int == int == int
因此,写入**q
与写入*p
等同于写入i
。写入 *q
与写入 p
相同。
以下内容可能有帮助,也可能没有帮助。
我写了一个小实用程序来显示内存中各种项目的内容,我将用它来说明 p = &i
和 *p = i
之间的区别。
首先,这是测试程序:
#include <stdio.h>
#include "dumper.h"
int main( void )
{
int i = 0, j = 0, *p = NULL;
char *names[] = { "i", "j", "p", "*p"};
void *addrs[] = { &i, &j, &p, NULL };
size_t sizes[] = { sizeof i, sizeof j, sizeof p, sizeof *p };
puts( "Before any assignments: ");
dumper( names, addrs, sizes, 3, stdout );
p = &i;
addrs[3] = p;
puts( "After p = &i: " );
dumper( names, addrs, sizes, 4, stdout );
*p = 42;
puts( "After *p = 42: " );
dumper( names, addrs, sizes, 4, stdout );
p = &j;
addrs[3] = p;
puts( "After p = &j: " );
dumper( names, addrs, sizes, 4, stdout );
*p = 10;
puts( "After *p = 10: " );
dumper( names, addrs, sizes, 4, stdout );
return 0;
}
dumper
函数显示当时内存中各种对象的状态。
所以,我们从声明开始:
int i = 0, j = 0, *p = 0;
i
和 j
是常规的 int
,p
是指向 int
的 指针 。这意味着 p
中存储的值是其他 int
对象的地址。这是此时内存中的内容:
Item Address 00 01 02 03
---- ------- -- -- -- --
i 0x7ffee3d07a28 00 00 00 00 ....
j 0x7ffee3d07a24 00 00 00 00 ....
p 0x7ffee3d07a18 00 00 00 00 ....
0x7ffee3d07a1c 00 00 00 00 ....
i
占用地址0x7ffee3d07a28
开始的4个字节1,j
占用地址0x7ffee3d07a24
开始的四个字节, p
从地址 0x7ffee3d07a18
开始占用 8 个字节。所有三个对象当前都存储 0 个值。
接下来,我们执行语句
p = &i;
这会将 i
的 地址 存储到 p
。以下是事后的情况:
Item Address 00 01 02 03
---- ------- -- -- -- --
i 0x7ffee3d07a28 00 00 00 00 ....
j 0x7ffee3d07a24 00 00 00 00 ....
p 0x7ffee3d07a18 28 7a d0 e3 (z..
0x7ffee3d07a1c fe 7f 00 00 ....
*p 0x7ffee3d07a28 00 00 00 00 ....
p
现在存储 i
2 的地址,而不是存储全零。请注意 expression *p
与 object i
3[= 具有相同的有效地址168=]。
现在我们执行语句
*p = 42;
我们的记忆现在是这样的:
Item Address 00 01 02 03
---- ------- -- -- -- --
i 0x7ffee3d07a28 2a 00 00 00 *...
j 0x7ffee3d07a24 00 00 00 00 ....
p 0x7ffee3d07a18 28 7a d0 e3 (z..
0x7ffee3d07a1c fe 7f 00 00 ....
*p 0x7ffee3d07a28 2a 00 00 00 *...
i
的最低有效字节现在存储值 0x2a
,即十六进制的 42
。请注意 *p
显示相同的内容。同样,在大多数情况下,*p
等同于 i
。
现在,我们把j
的地址赋值给p
:
p = &j;
现在世界的状态是这样的:
Item Address 00 01 02 03
---- ------- -- -- -- --
i 0x7ffee3d07a28 2a 00 00 00 *...
j 0x7ffee3d07a24 00 00 00 00 ....
p 0x7ffee3d07a18 24 7a d0 e3 $z..
0x7ffee3d07a1c fe 7f 00 00 ....
*p 0x7ffee3d07a24 00 00 00 00 ....
p
现在存储 j
的地址,*p
现在等同于 j
。我们通过将 10
分配给 *p
:
来完成
*p = 10;
这给我们留下了
Item Address 00 01 02 03
---- ------- -- -- -- --
i 0x7ffee3d07a28 2a 00 00 00 *...
j 0x7ffee3d07a24 0a 00 00 00 ....
p 0x7ffee3d07a18 24 7a d0 e3 $z..
0x7ffee3d07a1c fe 7f 00 00 ....
*p 0x7ffee3d07a24 0a 00 00 00 ....
j
现在存储值 0x0a
,它是 10
的十六进制值。同样,表达式 *p
等同于 j
。
- 在大多数系统上,地址会从 运行 运行 变化,所以不要太在意确切的地址值。
- x86 是 little-endian,所以 least 有效字节是寻址字节。这意味着值读取 "backwards" - 从左到右,从下到上。
- 这是一个有点戏剧性的许可 - 表达式 没有这样的地址。这只是为了说明表达式
*p
在大多数情况下实际上与 i
相同。
我在我的C编程书上找到了这段代码:
int i = 42;
int *p;
p = &i; // & is address of sign
*p = i; // * is dereference sign
"p = &i"和"*p = i"有区别吗?? "p"使用这两个表达式会不会有不同的特点???
编辑:因为这段代码只是试图解释指针的概念,所以它不可运行...所以这两个赋值的顺序在这种情况下不相关...抱歉让事情变得模糊。 ..
Is there any differences between “p = &i” and “*p = i” while assigning the address int “i” to a pointer “p”
是的,有很大的不同。只有 p = &i
表示 "assign the address of i
to p
".
另一方面 *p = i
表示 "assign the value of i
to the value at the address that is stored in p
"。你可以通过一个简单的例子看到结果:
int i = 42;
int* p;
p = &i;
printf("%d", i);
*p = 5;
printf("%d", i);
int j = 3;
printf("%d %d", i, j);
p = &j;
*p = i;
printf("%d %d", i, j);
首先,快速总结 - 给定声明
int i, *p;
和声明
p = &i;
则下列说法成立:
p == &i // int * == int *
*p == i // int == int
您已将 i
的 地址 分配给 p
。因此,表达式 *p
和 i
的计算结果相同。给*p
赋值和给i
赋值是一样的,从*p
读一个值和从i
读一个值是一样的。如果你后来做了类似
*p = 10;
那么这就和写一样了
i = 10;
IOW,您正在为 p
指向 的事物分配一个新值。
如果我们引入多级间接寻址,例如:
int i;
int *p = &i;
int **q = &p;
则下列皆为真:
q == &p // int ** == int **
*q == p == &i // int * == int * == int *
**q == *p == i // int == int == int
因此,写入**q
与写入*p
等同于写入i
。写入 *q
与写入 p
相同。
以下内容可能有帮助,也可能没有帮助。
我写了一个小实用程序来显示内存中各种项目的内容,我将用它来说明 p = &i
和 *p = i
之间的区别。
首先,这是测试程序:
#include <stdio.h>
#include "dumper.h"
int main( void )
{
int i = 0, j = 0, *p = NULL;
char *names[] = { "i", "j", "p", "*p"};
void *addrs[] = { &i, &j, &p, NULL };
size_t sizes[] = { sizeof i, sizeof j, sizeof p, sizeof *p };
puts( "Before any assignments: ");
dumper( names, addrs, sizes, 3, stdout );
p = &i;
addrs[3] = p;
puts( "After p = &i: " );
dumper( names, addrs, sizes, 4, stdout );
*p = 42;
puts( "After *p = 42: " );
dumper( names, addrs, sizes, 4, stdout );
p = &j;
addrs[3] = p;
puts( "After p = &j: " );
dumper( names, addrs, sizes, 4, stdout );
*p = 10;
puts( "After *p = 10: " );
dumper( names, addrs, sizes, 4, stdout );
return 0;
}
dumper
函数显示当时内存中各种对象的状态。
所以,我们从声明开始:
int i = 0, j = 0, *p = 0;
i
和 j
是常规的 int
,p
是指向 int
的 指针 。这意味着 p
中存储的值是其他 int
对象的地址。这是此时内存中的内容:
Item Address 00 01 02 03
---- ------- -- -- -- --
i 0x7ffee3d07a28 00 00 00 00 ....
j 0x7ffee3d07a24 00 00 00 00 ....
p 0x7ffee3d07a18 00 00 00 00 ....
0x7ffee3d07a1c 00 00 00 00 ....
i
占用地址0x7ffee3d07a28
开始的4个字节1,j
占用地址0x7ffee3d07a24
开始的四个字节, p
从地址 0x7ffee3d07a18
开始占用 8 个字节。所有三个对象当前都存储 0 个值。
接下来,我们执行语句
p = &i;
这会将 i
的 地址 存储到 p
。以下是事后的情况:
Item Address 00 01 02 03
---- ------- -- -- -- --
i 0x7ffee3d07a28 00 00 00 00 ....
j 0x7ffee3d07a24 00 00 00 00 ....
p 0x7ffee3d07a18 28 7a d0 e3 (z..
0x7ffee3d07a1c fe 7f 00 00 ....
*p 0x7ffee3d07a28 00 00 00 00 ....
p
现在存储 i
2 的地址,而不是存储全零。请注意 expression *p
与 object i
3[= 具有相同的有效地址168=]。
现在我们执行语句
*p = 42;
我们的记忆现在是这样的:
Item Address 00 01 02 03
---- ------- -- -- -- --
i 0x7ffee3d07a28 2a 00 00 00 *...
j 0x7ffee3d07a24 00 00 00 00 ....
p 0x7ffee3d07a18 28 7a d0 e3 (z..
0x7ffee3d07a1c fe 7f 00 00 ....
*p 0x7ffee3d07a28 2a 00 00 00 *...
i
的最低有效字节现在存储值 0x2a
,即十六进制的 42
。请注意 *p
显示相同的内容。同样,在大多数情况下,*p
等同于 i
。
现在,我们把j
的地址赋值给p
:
p = &j;
现在世界的状态是这样的:
Item Address 00 01 02 03
---- ------- -- -- -- --
i 0x7ffee3d07a28 2a 00 00 00 *...
j 0x7ffee3d07a24 00 00 00 00 ....
p 0x7ffee3d07a18 24 7a d0 e3 $z..
0x7ffee3d07a1c fe 7f 00 00 ....
*p 0x7ffee3d07a24 00 00 00 00 ....
p
现在存储 j
的地址,*p
现在等同于 j
。我们通过将 10
分配给 *p
:
*p = 10;
这给我们留下了
Item Address 00 01 02 03
---- ------- -- -- -- --
i 0x7ffee3d07a28 2a 00 00 00 *...
j 0x7ffee3d07a24 0a 00 00 00 ....
p 0x7ffee3d07a18 24 7a d0 e3 $z..
0x7ffee3d07a1c fe 7f 00 00 ....
*p 0x7ffee3d07a24 0a 00 00 00 ....
j
现在存储值 0x0a
,它是 10
的十六进制值。同样,表达式 *p
等同于 j
。
- 在大多数系统上,地址会从 运行 运行 变化,所以不要太在意确切的地址值。
- x86 是 little-endian,所以 least 有效字节是寻址字节。这意味着值读取 "backwards" - 从左到右,从下到上。
- 这是一个有点戏剧性的许可 - 表达式 没有这样的地址。这只是为了说明表达式
*p
在大多数情况下实际上与i
相同。