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

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


当前回答

指针让很多人感到困惑的原因是它们大多没有计算机架构背景。由于许多人似乎不知道计算机(机器)是如何实际实现的——在C/ c++中工作似乎很陌生。

一个练习是要求他们实现一个简单的基于字节码的虚拟机(在任何他们选择的语言中,python都很适合这个),其中的指令集集中于指针操作(加载、存储、直接/间接寻址)。然后要求他们为该指令集编写简单的程序。

任何需要比简单加法稍微多一点的东西都会涉及到指针,它们肯定会得到指针。

其他回答

指针的复杂性超出了我们可以轻易教授的范围。让学生们互相指指点点和使用写有家庭住址的纸都是很好的学习工具。他们在介绍基本概念方面做得很好。事实上,学习指针的基本概念对于成功使用指针是至关重要的。然而,在产品代码中,通常会遇到比这些简单演示所能封装的复杂得多的场景。

我参与过的系统中,我们有一个结构指向另一个结构指向另一个结构。其中一些结构还包含嵌入式结构(而不是指向其他结构的指针)。这就是指针真正令人困惑的地方。如果你有多个间接层,你最终会得到这样的代码:

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).

我认为大学为帮助学生学习指针所能做的最好的事情就是使用良好的演示,并结合需要使用指针的项目。对于指针的理解,一个困难的项目要比上千个演示做得多。演示可以让您对指针有一个浅显的理解,但要深刻地理解指针,您必须真正地使用它们。

The problem with pointers is not the concept. It's the execution and language involved. Additional confusion results when teachers assume that it's the CONCEPT of pointers that's difficult, and not the jargon, or the convoluted mess C and C++ makes of the concept. So vast amounts of effort are poored into explaining the concept (like in the accepted answer for this question) and it's pretty much just wasted on someone like me, because I already understand all of that. It's just explaining the wrong part of the problem.

为了让你知道我是怎么来的,我是一个非常理解指针的人,我可以在汇编语言中熟练地使用它们。因为在汇编语言中,它们不被称为指针。它们被称为地址。当我在C语言中编程和使用指针时,我犯了很多错误,并感到非常困惑。我还没弄清楚。让我给你们举个例子。

当一个api说:

int doIt(char *buffer )
//*buffer is a pointer to the buffer

它想要什么?

它可能想要:

表示缓冲区地址的数字

(给它,我说doIt(mybuffer),还是doIt(* mybuffer) ?)

表示缓冲区地址的一种数字

(doIt(&mybuffer) or doIt(mybuffer) or doIt(*mybuffer)?)

表示缓冲区地址的地址的数字

(可能是doIt(&mybuffer)。还是doIt(&&mybuffer) ?甚至doIt(&&&mybuffer))

and so on, and the language involved doesn't make it as clear because it involves the words "pointer" and "reference" that don't hold as much meaning and clarity to me as "x holds the address to y" and "this function requires an address to y". The answer additionally depends on just what the heck "mybuffer" is to begin with, and what doIt intends to do with it. The language doesn't support the levels of nesting that are encountered in practice. Like when I have to hand a "pointer" in to a function that creates a new buffer, and it modifies the pointer to point at the new location of the buffer. Does it really want the pointer, or a pointer to the pointer, so it knows where to go to modify the contents of the pointer. Most of the time I just have to guess what is meant by "pointer" and most of the time I'm wrong, regardless of how much experience I get at guessing.

指针重载了。指针是指向值的地址吗?或者它是一个将地址保存到值的变量。当一个函数需要一个指针时,它是想要指针变量保存的地址,还是指针变量的地址? 我困惑。

我发现Ted Jensen的“C中的指针和数组教程”是学习指针的极好的资源。它分为10节课,从解释指针是什么(以及它们是用来干什么的)开始,到以函数指针结束。http://web.archive.org/web/20181011221220/http://home.netcom.com:80/~tjensen/ptr/cpoint.htm

接着,Beej的《网络编程指南》教授了Unix套接字API,从中你可以开始做一些真正有趣的事情。http://beej.us/guide/bgnet/

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

所以我说,假设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++中指针的管理可能是不必要的复杂。