为什么指针是许多刚开始学习C或c++,甚至上了大学的学生困惑的主要因素?有没有什么工具或思维过程可以帮助你理解指针在变量、函数和级别之外是如何工作的?

有什么好的实践可以让人达到“啊哈,我懂了”的水平,而不会让他们陷入整体概念中?基本上,就是模拟场景。


当前回答

我想我应该在这个列表中添加一个类比,当我作为计算机科学导师解释指针时(回到过去),我发现它非常有用;首先,让我们:


做好准备:

考虑一个有3个车位的停车场,这些车位是编号的:

-------------------
|     |     |     |
|  1  |  2  |  3  |
|     |     |     |

在某种程度上,这就像内存位置,它们是连续的和连续的。有点像数组。现在它们中没有汽车,所以它就像一个空数组(parking_lot[3] ={0})。


添加数据

停车场永远不会空着太久……如果有,那就没有意义了,也没有人会去建造。假设随着时间推移,停车场里停满了3辆车,一辆蓝色的,一辆红色的,一辆绿色的

   1     2     3
-------------------
| o=o | o=o | o=o |
| |B| | |R| | |G| |
| o-o | o-o | o-o |

这些车都是同一类型(car),所以一种思考方法是,我们的车是某种数据(比如int),但它们有不同的值(蓝色,红色,绿色;这可以是一个颜色枚举)


进入指针

现在如果我带你到这个停车场,让你给我找一辆蓝色的车,你伸出一根手指,指着点1的一辆蓝色的车。这就像获取一个指针并将其分配给一个内存地址(int *finger = parking_lot)

你的手指(指针)不是我问题的答案。看你的手指什么也不能告诉我,但如果我看你手指指向的地方(取消指针指向),我就能找到我要找的车(数据)。


重新分配指针

现在我可以让你找到一辆红色的车,你可以把你的手指转向一辆新车。现在您的指针(与之前的指针相同)正在向我显示相同类型(汽车)的新数据(可以找到红色汽车的停车位)。

指针在物理上没有变化,它仍然是你的手指,只是它显示给我的数据变了。(“车位”地址)


双指针(或指向指针的指针)

这也适用于多个指针。我可以问指向红色汽车的指针在哪里,你可以用另一只手用一根手指指向第一个手指。(这就像int **finger_two = &finger)

现在如果我想知道蓝色的车在哪里,我可以顺着食指的方向到第二根手指,到那辆车(数据)。


悬空指针

现在让我们假设你感觉自己很像一座雕像,你想一直用手指着那辆红色的车。如果那辆红色汽车开走了怎么办?

   1     2     3
-------------------
| o=o |     | o=o |
| |B| |     | |G| |
| o-o |     | o-o |

你的指针仍然指向红色汽车的位置,但它已经不在了。假设一辆新车停在那里……一辆橙色的汽车。现在如果我再问你,“红色的车在哪里”,你仍然指着那里,但现在你错了。那不是红色的车,那是橙色的。


指针的算术

好的,你仍然指着第二个停车位(现在被橙色车占据了)

   1     2     3
-------------------
| o=o | o=o | o=o |
| |B| | |O| | |G| |
| o-o | o-o | o-o |

我现在有个新问题…我想知道下一个停车位的车是什么颜色。你可以看到你指向点2,所以你只要加1,你就指向下一个点。(手指+1),现在因为我想知道那里的数据是什么,你必须检查那个点(不仅仅是手指),所以你可以遵从指针(*(手指+1)),以看到那里有一辆绿色的汽车(该位置的数据)

其他回答

我认为,使指针难以学习的原因是,直到你熟悉了指针的概念,即“在这个内存位置是一组表示int型,double型,字符等的位”。

当你第一次看到一个指针时,你并不知道那个内存位置上有什么。“什么意思,里面有地址?”

我不同意“要么得到要么得不到”的观点。

当你开始发现它们的真正用途时(比如不要将大结构传递到函数中),它们就会变得更容易理解。

一个带有一组很好的图表的教程示例极大地帮助理解指针。

Joel Spolsky在他的《面试指南》文章中提出了一些关于理解指针的好观点:

出于某种原因,大多数人似乎生来就没有大脑中理解指针的那部分。这是一个天赋问题,而不是技能问题——它需要一种复杂的双重间接思维形式,而有些人就是做不到。

我喜欢用数组和下标来解释它——人们可能不熟悉指针,但他们通常都知道下标是什么。

所以我说,假设RAM是一个数组(你只有10个字节的RAM):

unsigned char RAM[10] = { 10, 14, 4, 3, 2, 1, 20, 19, 50, 9 };

然后,指向变量的指针实际上只是该变量在RAM中的第一个字节的索引。

因此,如果你有一个指针/索引unsigned char index = 2,那么这个值显然是第三个元素,或者数字4。指针指向指针的指针是指将该数字本身用作索引,如RAM[RAM[index]]。

我会在纸上的列表上画一个数组,然后用它来显示一些东西,比如指向同一个内存的许多指针、指针算术、指针到指针等等。

我认为这可能是语法问题。指针的C/ c++语法似乎不一致,而且比实际需要的更复杂。

具有讽刺意味的是,真正帮助我理解指针的是c++标准模板库中迭代器的概念。这很讽刺,因为我只能假设迭代器被认为是指针的泛化。

有时候,只有当你学会忽略树木时,你才能看到森林。

它之所以如此难以理解,并不是因为它是一个复杂的概念,而是因为语法不一致。

int *mypointer;

您首先了解到变量创建的最左边部分定义了变量的类型。在C和c++中,指针声明不是这样工作的。相反,他们说变量指向左边的类型。在这种情况下:*mypointer指向int类型。

我没有完全掌握指针,直到我尝试在c#中使用它们(不安全),它们以完全相同的方式工作,但具有逻辑和一致的语法。指针本身就是一个类型。这里mypointer是一个指向int型的指针。

int* mypointer;

甚至不要让我开始函数指针…