我正在按照本教程关于指针如何工作.
让我引用相关段落:
Run Code Online (Sandbox Code Playgroud)int i = 5, j = 6, k = 7; int *ip1 = &i, *ip2 = &j;现在我们可以设置
Run Code Online (Sandbox Code Playgroud)int **ipp = &ip1;并
ipp指向ip1哪些点i.*ippisip1,and**ippisi,or 5.我们可以用我们熟悉的盒子和箭头符号来说明这种情况,如下所示:
如果那时我们说
Run Code Online (Sandbox Code Playgroud)*ipp = ip2;我们已经改变了指向
ipp(即ip1)的指针以包含一个副本ip2,因此it(ip1)现在指向j:
我的问题是:为什么在第二张图片中ipp仍然指向ip1但不是ip2?
Rob*_*nes 142
忘记关于指向类比的第二个问题.指针真正包含的是内存地址.的&是操作者"的地址" -即它在一个对象的存储器返回地址.该*运营商给你的对象的指针指,即给予包含地址的指针,在这一点内存地址返回的对象.所以,当你做*ipp = ip2,你在做什么是*ipp获取对象举行的地址在ipp这 ip1,然后分配给ip1存储于价值ip2,这是地址j.
简单
& - >地址
*- >价值在
Ski*_*izz 43
因为您更改了指向ipp的值而不是值ipp.因此,ipp仍指向ip1(值ipp),ip1现在的值与值相同ip2,因此它们都指向j.
这个:
*ipp = ip2;
Run Code Online (Sandbox Code Playgroud)
是相同的:
ip1 = ip2;
Run Code Online (Sandbox Code Playgroud)
mic*_*ang 21
希望这段代码可以提供帮助.
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
int i = 5, j = 6, k = 7;
int *ip1 = &i, *ip2 = &j;
int** ipp = &ip1;
printf("address of value i: %p\n", &i);
printf("address of value j: %p\n", &j);
printf("value ip1: %p\n", ip1);
printf("value ip2: %p\n", ip2);
printf("value ipp: %p\n", ipp);
printf("address value of ipp: %p\n", *ipp);
printf("value of address value of ipp: %d\n", **ipp);
*ipp = ip2;
printf("value ipp: %p\n", ipp);
printf("address value of ipp: %p\n", *ipp);
printf("value of address value of ipp: %d\n", **ipp);
}
Run Code Online (Sandbox Code Playgroud)
它输出:

Eri*_*ert 21
像C标签中的大多数初学者问题一样,这个问题可以通过回到第一原则来回答:
&操作者打开一可变成指针.*操作者接通一个指针到一个变量.(从技术上讲,我应该说"左值"而不是"变量",但我觉得将可变存储位置描述为"变量"更为明确.)
所以我们有变量:
int i = 5, j = 6;
int *ip1 = &i, *ip2 = &j;
Run Code Online (Sandbox Code Playgroud)
变量ip1 包含一个指针.在&操作者接通i到一个指针和该指针值被分配给ip1.所以ip1 包含一个指针i.
变量ip2 包含一个指针.在&操作者接通j到一个指针和该指针被分配给ip2.所以ip2 包含一个指针j.
int **ipp = &ip1;
Run Code Online (Sandbox Code Playgroud)
变量ipp包含一个指针.在&操作者接通变量ip1成一个指针和该指针值被分配给ipp.所以ipp包含一个指针ip1.
让我们总结一下这个故事:
i 包含5j 包含6ip1包含"指针i"ip2包含"指针j"ipp包含"指针ip1"现在我们说
*ipp = ip2;
Run Code Online (Sandbox Code Playgroud)
的*操作者打开一指针返回到一个变量.我们获取值ipp,这是"指针ip1并将其转换为变量.ip1当然,什么变量?
因此,这只是另一种说法
ip1 = ip2;
Run Code Online (Sandbox Code Playgroud)
所以我们获取的值ip2.它是什么?"指向j".我们将指针值赋给ip1,所以ip1现在是"指针j"
我们只改变了一件事:价值ip1:
i 包含5j 包含6ip1包含"指针j"ip2包含"指针j"ipp包含"指针ip1"为什么
ipp还指向ip1而不是ip2?
分配给变量时,变量会发生变化.计算作业; 变量没有比赋值更多的变化!您可以通过分配开始i,j,ip1,ip2和ipp.然后你分配给*ipp,我们已经看到的意思与"分配给ip1" 相同.由于你没有ipp第二次分配,它没有改变!
如果你想改变ipp那么你必须实际分配给ipp:
ipp = &ip2;
Run Code Online (Sandbox Code Playgroud)
例如.
Lun*_*din 12
我个人的观点是,箭头指向这种方式的图片或指针更难以理解.它确实使它们看起来像一些抽象的,神秘的实体.他们不是.
与计算机中的其他所有内容一样,指针是数字.名称"指针"只是一种说"含有地址的变量"的奇特方式.
因此,让我通过解释计算机实际工作原理来解决问题.
我们有一个int,它有名称i和值5.它存储在内存中.就像存储在内存中的所有内容一样,它需要一个地址,否则我们将无法找到它.让我们说i最终在地址0x12345678,其伙伴j价值6在它之后结束.假设32位CPU,其中int是4个字节,指针是4个字节,那么变量存储在物理内存中,如下所示:
Address Data Meaning
0x12345678 00 00 00 05 // The variable i
0x1234567C 00 00 00 06 // The variable j
Run Code Online (Sandbox Code Playgroud)
现在我们想指出这些变量.我们创建一个指向int int* ip1,和一个的指针int* ip2.就像计算机中的所有内容一样,这些指针变量也会在内存中的某处分配.让我们假设它们最终会在内存中的下一个相邻地址结束j.我们设置指针以包含先前分配的变量ip1=&i;的地址:("将i的地址复制到ip1")和ip2=&j.这些线之间发生的事情是:
Address Data Meaning
0x12345680 12 34 56 78 // The variable ip1(equal to address of i)
0x12345684 12 34 56 7C // The variable ip2(equal to address of j)
Run Code Online (Sandbox Code Playgroud)
所以我们得到的只是一些包含数字的4字节内存块.在任何地方都没有任何神秘或神奇的箭头.
实际上,仅通过查看内存转储,我们无法判断地址0x12345680是否包含int或int*.不同之处在于我们的程序选择如何使用存储在此地址的内容.(我们程序的任务实际上只是告诉CPU如何处理这些数字.)
然后我们添加另一个间接级别int** ipp = &ip1;.再一次,我们只获得了一大块内存:
Address Data Meaning
0x12345688 12 34 56 80 // The variable ipp
Run Code Online (Sandbox Code Playgroud)
这种模式似乎很熟悉.另一个包含数字的4个字节的块.
现在,如果我们有一个上述虚构的小RAM的内存转储,我们可以手动检查这些指针指向的位置.我们查看存储在ipp变量地址的内容并找到内容0x12345680.这当然ip1是存储地址.我们可以去那个地址,检查那里的内容,找到地址i,最后我们可以到那个地址找到号码5.
因此,如果我们获取ipp的内容*ipp,我们将获得指针变量的地址ip1.通过编写*ipp=ip2我们将ip2复制到ip1,它相当于ip1=ip2.无论哪种情况,我们都会得到
Address Data Meaning
0x12345680 12 34 56 7C // The variable ip1
0x12345684 12 34 56 7C // The variable ip2
Run Code Online (Sandbox Code Playgroud)
(这些示例是为大端CPU提供的)
注意分配:
ipp = &ip1;
Run Code Online (Sandbox Code Playgroud)
结果ipp指向ip1.
所以为了ipp指出ip2,我们应该以类似的方式改变,
ipp = &ip2;
Run Code Online (Sandbox Code Playgroud)
我们显然没有这样做.相反,我们正在改变指向的地址的值ipp.
通过做下面的事情
*ipp = ip2;
Run Code Online (Sandbox Code Playgroud)
我们只是替换存储的值ip1.
ipp = &ip1,意思是*ipp = ip1 = &i,
现在,*ipp = ip2 = &j.
所以,*ipp = ip2基本上是一样的ip1 = ip2.
ipp = &ip1;
Run Code Online (Sandbox Code Playgroud)
以后的任务没有改变它的价值ipp.这就是为什么它仍然指向ip1.
你所做的事情*ipp,即与之相关ip1,并没有改变ipp指向的事实ip1.
小智 5
因为当你说
*ipp = ip2
Run Code Online (Sandbox Code Playgroud)
你说的是'指向的对象ipp'指向指向的内存方向ip2.
你不是说ipp要指出的ip2.
我的问题是:为什么在第二张图片中,ipp仍然指向ip1而不是ip2?
你放了漂亮的照片,我打算做一个漂亮的ascii艺术:
就像@ Robert-S-Barnes在他的回答中所说:忘记指针,什么指向什么,但从记忆的角度来思考.基本上,它int*表示它包含变量的地址,并且int**包含包含变量地址的变量的地址.然后你可以使用指针的代数来访问值或地址:&foo意思address of foo和*foo手段value of the address contained in foo.
因此,作为关于处理内存的指针,实际制作"有形"的最佳方法是显示指针代数对内存的作用.
所以,这是你的程序的内存(为了示例的目的简化):
name: i j ip1 ip2 ipp
addr: 0 1 2 3 4
mem : [ | | | | ]
Run Code Online (Sandbox Code Playgroud)
当你做初始代码时:
int i = 5, j = 6;
int *ip1 = &i, *ip2 = &j;
Run Code Online (Sandbox Code Playgroud)
这是你的记忆的样子:
name: i j ip1 ip2
addr: 0 1 2 3
mem : [ 5| 6| 0| 1]
Run Code Online (Sandbox Code Playgroud)
那里,你可以看到ip1和ip2得到的地址i和j和ipp仍然不存在.不要忘记,地址只是以特殊类型存储的整数.
然后你声明并定义ipp如下:
int **ipp = &ip1;
Run Code Online (Sandbox Code Playgroud)
所以这是你的记忆:
name: i j ip1 ip2 ipp
addr: 0 1 2 3 4
mem : [ 5| 6| 0| 1| 2]
Run Code Online (Sandbox Code Playgroud)
然后,您将更改存储在ipp其中的地址所指向的值,即存储在ip1以下位置的地址:
*ipp = ip2;
Run Code Online (Sandbox Code Playgroud)
程序的记忆是
name: i j ip1 ip2 ipp
addr: 0 1 2 3 4
mem : [ 5| 6| 1| 1| 2]
Run Code Online (Sandbox Code Playgroud)
注意:作为int*一种特殊类型,我更喜欢总是避免在同一行上声明多个指针,因为我认为int *x;或者int *x, *y;表示法可能会产生误导.我更喜欢写int* x; int* y;
HTH
| 归档时间: |
|
| 查看次数: |
10332 次 |
| 最近记录: |