为什么指针是许多刚开始学习C或c++,甚至上了大学的学生困惑的主要因素?有没有什么工具或思维过程可以帮助你理解指针在变量、函数和级别之外是如何工作的?
有什么好的实践可以让人达到“啊哈,我懂了”的水平,而不会让他们陷入整体概念中?基本上,就是模拟场景。
为什么指针是许多刚开始学习C或c++,甚至上了大学的学生困惑的主要因素?有没有什么工具或思维过程可以帮助你理解指针在变量、函数和级别之外是如何工作的?
有什么好的实践可以让人达到“啊哈,我懂了”的水平,而不会让他们陷入整体概念中?基本上,就是模拟场景。
当前回答
我认为理解指针的主要障碍是糟糕的老师。
几乎每个人都被教导过关于指针的谎言:它们只不过是内存地址,或者它们允许你指向任意位置。
当然,他们很难理解,危险,半魔法。
这些都不是真的。指针实际上是相当简单的概念,只要你坚持c++语言对它们的描述,不要给它们灌输“通常”在实践中会起作用的属性,但语言却不能保证,因此不是指针实际概念的一部分。
几个月前,我试图在这篇博客文章中对此进行解释——希望它能帮助到一些人。
(请注意,在有人对我说学究气之前,是的,c++标准确实说指针表示内存地址。但它并没有说“指针是内存地址,而且只是内存地址,可以与内存地址互换使用或认为”。区别很重要)
其他回答
我不认为指针本身令人困惑。大多数人都能理解这个概念。现在你能想到多少个指针或者你能适应多少个间接层次。不需要太多就能让人崩溃。它们可能会被程序中的错误意外更改,这也会使它们在代码中出错时很难调试。
指针的复杂性超出了我们可以轻易教授的范围。让学生们互相指指点点和使用写有家庭住址的纸都是很好的学习工具。他们在介绍基本概念方面做得很好。事实上,学习指针的基本概念对于成功使用指针是至关重要的。然而,在产品代码中,通常会遇到比这些简单演示所能封装的复杂得多的场景。
我参与过的系统中,我们有一个结构指向另一个结构指向另一个结构。其中一些结构还包含嵌入式结构(而不是指向其他结构的指针)。这就是指针真正令人困惑的地方。如果你有多个间接层,你最终会得到这样的代码:
widget->wazzle.fizzle = fazzle.foozle->wazzle;
它很快就会让人感到困惑(想象更多的线,可能还有更多的关卡)。再加上指针数组和节点到节点的指针(树、链表),情况就更糟了。我曾见过一些非常优秀的开发人员在开始开发这样的系统时迷失了方向,甚至是那些非常了解基础知识的开发人员。
Complex structures of pointers don't necessarily indicate poor coding, either (though they can). Composition is a vital piece of good object-oriented programming, and in languages with raw pointers, it will inevitably lead to multi-layered indirection. Further, systems often need to use third-party libraries with structures which don't match each other in style or technique. In situations like that, complexity is naturally going to arise (though certainly, we should fight it as much as possible).
我认为大学为帮助学生学习指针所能做的最好的事情就是使用良好的演示,并结合需要使用指针的项目。对于指针的理解,一个困难的项目要比上千个演示做得多。演示可以让您对指针有一个浅显的理解,但要深刻地理解指针,您必须真正地使用它们。
当我只懂c++的时候,我可以使用指针。从试错中,我知道在某些情况下应该做什么,不应该做什么。但是让我完全理解的是汇编语言。如果您对自己编写的汇编语言程序进行了一些严肃的指令级调试,那么您应该能够理解很多东西。
在我的第一节compp Sci课上,我们做了以下练习。当然,这是一个大约有200名学生的演讲厅……
教授在黑板上写道:int john;
约翰站起来
教授写道:int *sally = &john;
莎莉站起来,指着约翰
int *bill = sally;
比尔站起来,指着约翰
教授:int sam;
山姆站起来
教授:bill = &sam;
比尔现在指向山姆。
我想你已经明白了。我想我们花了一个小时来做这个,直到我们复习了指针赋值的基础知识。
为了使事情更混乱一点,有时你必须使用句柄而不是指针。句柄是指向指针的指针,因此后端可以移动内存中的内容以整理堆。如果指针在例程中间发生了变化,那么结果是不可预测的,因此您首先必须锁定句柄,以确保没有任何事情发生。
http://arjay.bc.ca/Modula-2/Text/Ch15/Ch15.8.html#15.8.5比我讲得更清楚一点。: -)