it-swarm.cn

指针有什么好的解释?

在您自己的学习中(您自己或上一堂课),当您最终真正理解指针时,您是否有一个“啊哈”时刻?您对初学者使用的解释是否似乎特别有效?

例如,当初学者第一次在C语言中遇到指针时,他们可能只添加&s和*s,直到它被编译为止(就像我自己曾经做的那样)。也许是一张图片,或者是一个非常有动机的例子,使指针为您或您的学生“点击”。那是什么,在那之前您尝试了什么却似乎没有用?是否有任何主题先决条件(例如结构或数组)?

换句话说,什么时候可以放心使用&s和*的含义?仅学习语法和术语或用例还不够,有时需要将想法内在化。


更新:到目前为止,我真的很喜欢这个答案;请让他们来。这里有很多不错的观点,但是我认为很多都是对我们自己的很好的解释/口号after我们已经概念化了。我正在寻找黎明时分的详细情况和情况。

例如:

我只是在语法上对C的指针有所了解。我听到我的两个朋友向另一个朋友解释了指针,后者问为什么struct与指针一起传递。第一个朋友谈到了如何引用和修改它,但这只是另一个朋友的简短评论,它打动了我:“它也更有效率。”我需要的最后一个概念上的转变是传递4个字节而不是16个字节。

72
Macneil

内存即网格图

通常我所做的是将内存表示为“网格”,以便我可以组成地址,突出显示不同的内存空间并在单元格中写入值(甚至更进一步,它们的二进制表示形式)并将内存中的指针链接到它们的值。指向。 (然后仍然提到这是一种简化)。

通常,对我大多数学生来说,这是一个“噢”时刻。

符号杂耍

然后,当让他们停止忘记如何使用&和*时,这非常简单:以与他们进行数学或物理计算相同的方式呈现。如果将以千米为单位的距离除以以小时为单位的时间,则将得到以km/h为单位的速度。有什么需要注意的。简单。

printf到救援

仅做一些基本的示例以视觉方式代表您对这些内容的解释,就会使他们感到满意,使他们感到安慰,或者使他们有机会说“啊,我不明白”。

广泛

覆盖简单类型的指针,并确保它们了解数据类型的寻址和大小之间的区别,然后是结构,然后是数组以及多个级别。

然后开始指针运算。


附录:递归

我通常使用视觉表示类似地解释递归。让他们使用写单个字符的预制函数打印字母,然后要求他们仅改变两行就以相反的顺序打印它。

通常会有一个“什么……?”此刻,当您在printf中仅添加另一个参数以打印数字值并缩进步骤时,它就松了一口气。


替代方案:玩偶模型和水杯

我实际上在大学里有一些同事,向学生展示了一个视频,用play-doh粘贴解释了指针和内存访问。尽管我从来没有真正使用过这种技术,但是它非常聪明而且做得很好,除了非常年轻的学习者(对学习编程感兴趣)(但是通常我不会引导他们过早使用指针来学习语言)。基本上使用play-doh的小球,您可以将它们附加到表示内存空间的其他更大的play-doh的球上,并且可以组合在一起以链接它们(如在链接的数据结构中)或合并在一起(如在连续的中)内存空间)。为指向的存储空间使用不同的颜色,指针也有帮助。但是我仍然认为“将内存作为网格”的事情效果更好,因为您可以清楚地表明指向确实是“寻址”的问题,例如在“地图/网格”上。 Play-doh模式仍然使他们误以为事情确实在内存中彼此“接触”。

同事也直接使用了水杯的东西,但我不知道她是否提出了。这是一种有趣的方法,但我注意到许多学生对此解释感到困惑。类似于 DevSolo的咖啡杯技术 。但是我认为这实际上是一种误导,因为它会让学生混淆容器,数据结构,指针和数组。在我假设的一开始,对数组进行解释可能是一种有趣的方法,但是我不会坚持很长时间。

25
haylem

比我以前说的要聪明得多的人:

修女吴金仓问惠国六世:“我研究玛哈帕瑞尼瓦那经已很多年了,但我对很多领域还不太了解,请赐教。”

家长回答:“我是文盲。请给我读出字符,也许我能解释这个意思。”

修女说:“你甚至不能认出这些字符。那么你怎么能理解含义呢?”

“真理与语言无关。真理可以比喻为天空中的明亮月亮。在这种情况下,词语可以比喻为手指。手指可以指向月亮的位置。但是,手指不是月亮的所在。月亮。要看月亮,有必要凝视不出手指,对吗?

80
Frank Shearar

我发现图表非常有帮助。例:

pointer diagram


这种图表帮助我看到指针是它们自己的变量,但是包含一个值,该值是另一个对象的位置,即数组或字符串。另外,当用铅笔完成时,我可以用它在纸上或黑板/白板上跟踪程序。

46
Michael K

当我第一次“学习”有关指针的知识时,我对它有所了解。我的大学已经很长一段时间才做出决定,因此我开始以Java为中心学习课程,因此,当我的数据结构教授就C进行了一次讲座并要求我们使用指针实现XOR-List时,我感觉自己正在进入某种领域way在我头上。

我了解这个定义:

指针是包含变量地址的变量

但是我仍然不太了解这个概念。回顾过去,我认为它集中在三件事上:

  1. 确切的is内存位置是什么? (当时我没有参加计算机组织课程)

  2. 笨拙的语法(所以,嗯...为什么将其定义为“ int * ip”,但随后我将变量称为“ ip”?)

  3. 存储变量的地址而不是仅仅使用变量有什么好处?

直到我购买了K&R书并完成了我真正掌握的所有问题。除了我长期完成计算机组织课程(我认为在学习C语言之前必须先完成该课程)之外,部分原因还在于我意识到指针可以用于函数,数组,结构...做有用的事情,而不仅仅是存储普通变量的地址。

但是到目前为止,我的“ aha”时刻是K&R解释定义简单指针的笨拙语法的方式。我在整本书中都做了笔记(在其中我用自己的语言重新表达了本书的观点,以加深我的理解),这是与此相关的一个:

指针是包含变量地址的变量。使用“ *”运算符既可以定义也可以取消引用指针(产生存储在它指向的内存位置的值);该表达式是助记符。

Ex.: 
   int a;      /* Variable 'a' is an integer */

   int *ip;   /* Variable ip is a pointer and dereferencing it gives an integer.
                 In other words, the expression *ip is an int, so ip is a pointer
                 to an int */

一直以来,我一直感到无法完全掌握更高级的指针概念,直到我脑中根深蒂固。在完成该任务后,它无休止地困扰着我(顺便说一句,我做得不太好;))为什么在我(认为我)定义了“ * ip”之后就不存在“ * ip”。掌握这一点对于涉及指针(如函数指针)和更复杂的定义这样的更高级概念至关重要:

char (*(x())[])()

总而言之,我认为指针的概念要求:

  1. 基本了解计算机中的内存布局(以及内存是什么)。

  2. 了解指针有多强大(现实世界中的用法,而不仅仅是为了学习而学习的另一个抽象概念)。

  3. 通俗地解释象形文字称为“指针的定义”

因此,总的来说,我认为在学习指针时至少应该有3个“ aha”时刻。我仍然是一名学生,所以我想您会喜欢仍然(相对)刚开始学习该概念的人的观点。

32
Kevin

指针有点像您桌面上的应用程序快捷方式。删除快捷方式,目标仍然存在。启动快捷方式,目标即被启动。

我总是通过在桌面上简单地创建一个txt文件和该文件的两个快捷方式来解释其工作原理。复制和删除快捷方式后,您可以看到人们理解“引用”背后的想法。

一旦小组了解了快捷键背后的基本知识,您就可以开始按需解释指针。他们可能会很容易理解它。

19
Barfieldmv

8到10年前,我在社区大学教授了“ C”入门课程。这始终是一个有趣的话题。似乎最有效的方法是,在与同事讨论几次之后,就是用咖啡杯和手。

我将咖啡杯(或一行用于数组)的类比用作变量(它可以容纳某些东西)。然后,我用我的手,它也可以握住东西,或者通过伸出食指“指向”咖啡杯。

紧握的手是零,手指指向我的头(像是模拟枪)是悬空的指针。

然后,通过一些演示和调试器的调试,大多数人都点击了它。

14
DevSolo

当我听到“您如何掌握指针”的问题时,我真的很担心。我一直认为这个概念非常简单,并且语言的逻辑演变为程序员提供了强大的功能。

让我担心的是,我从未发现很难理解指针的概念。因此,当您一遍又一遍地“什么时候终于得到它”时,您开始思考:

我真的明白了吗?也许我从来没有做过?

也许这个概念似乎很棘手的原因是因为我们一直在告诉尚未碰到它们的每个人,指针是如此的困难,这里有一百种学习方法?

只是把那个想法抛诸脑后,我个人当然喜欢一个好的图表,而且 Steve Gibson总是在解释任何事情上做得非常出色

10
Marcus Whybrow

我从来没有对C中的指针有太多的问题,但这可能是因为我必须先学习汇编程序。实际上,不必再处理自己的地址,这真是一种解脱。所以也许答案(假设这是您正在教的东西)是给学生一种模拟的汇编语言供您使用。他们will在编写任何比“ Hello,world”更复杂的东西的过程中都会弄清楚。

7
Larry Coleman

指针是一个变量,其值是另一个变量的内存地址。

7
kirk.burleson

我如何真正了解指针?通过写一个简单的编译器大学一年级。

如何用外行术语解释指针?我喜欢存储在索引卡上的图书馆目录的(日期?)类比。每个卡(“指针”)都包含有关某本书(“数据”)所在位置的信息,但实际上并不包含该书本身。如果您修改卡(“指针算术”),它所做的只是更改它指向的书,并且对书本身没有影响-请注意不要弄乱地址,否则您可能会指向不存在的书甚至是错误的库。但是,如果遵循卡上的“地址”并转到库的适当部分(“取消引用指针”),则可以查看/修改书本。

6
Yevgeniy Brikman

已编辑以支持问题的修订要求

我对“指针后”理解(如果我没记错的话)的方法是这样的。从我还是 与BBC Micro混在一起 开始,我就具有一些简单的汇编编程经验,所以我将内存的概念定义为一堆盒子(参见下文)。这通过使用数组得到了加强。但是,我进入C语言世界,不得不处理字符串,这意味着指针。在BASIC中,这是微不足道的,在汇编程序中,我不需要使用它们,现在在经典C中,所有的都是指针和东西。啊,但是我可以像这样(用空终止)返回到数组:

char s[] = "Hello, world!";
printf("%s",s);

很好,这只是一个字符数组(在我的小世界里,每个字符8位),末尾有一个零字符以显示其结束位置。 printf只是获取该数组并对其进行打印。但是,如果我想将此字符串传递给函数怎么办?

void print_str(char* p) {
  printf("%s",p);
}

手册上说的是什么,但是那又是什么呢?嗯,char *表示“指向char的指针”。好...失去了我然后我发现char *使p等于s [0]。好的,我可以使用它,但是我仍然没有限制指针是什么。我的意思是,我该如何使用其中之一设置一些数据?再次转到手册...

char* p = "Hello World!";

当我写上面的文章时,我对自己说:“声明一个指向char的指针,并将其设置为等于此字符数组”。该指针以某种方式消除了对数组的需求。猜猜是编译器为我做了一些改变。那么如何使用该指针更改数组?我知道我可以使用阵列版本

 s[2] = 'L'; 

但是“指针说话”的含义是什么?再次转到该手册...

*(p+2) = 'L';

我想*只是表示“内存地址的内容”和(p+2)s[2]。这意味着指针p是……只是……一个……地址……b!

有启蒙的声音。我突然变了个指针(很久以前,我们的旧计时器直到后来才“增长”)。这只是间接的。


原版的:

好的,我的2c价值:

想象一下,内存是一堆盒子。每个盒子的侧面都有一个数字(地址)。每个框包含一个数字(内容)。您可以通过2种方式使用这些框:变量(我想要框N的内容),指针(我想要框N的内容无论框N是什么)。指针只是间接的。

对于涵盖您将需要知道的所有内容的大答案- 阅读此书

5
Gary Rowe

我将假设要学习指针的人知道普通变量是什么,以及它们如何在C中工作。现在,让我们尝试使用某些属性来定义指针-

  • 它们也是变量,但性质不同。假设可变空间中有两层。不同类型的普通变量位于上层,指针位于下层。像这个图

    alt text

  • 顾名思义,“指针”可以指向某物。就像我们的手指可以指向某个对象。他们指的是什么?这些是正常变量。简而言之,“指针指向普通变量”。

  • 像普通变量一样,指针也具有相同数量的类型,例如int,char或float。特定类型的指针只能指向相同类型的变量。
  • 指针可以指向一个变量,然后同一指针可以指向另一个变量。只是类型应该相同。因此,指针与某个变量的关联不是永久的,可以更改。
  • 那么,如何声明一个指针呢?几乎像普通变量一样。您必须在名称前加上星号(*)。喜欢-

    int *pointer;
    
  • 那么,指针如何与变量关联?使用 &运算符,如以下语句之前

    pointer = &variable;
    
  • 通过指向变量如何使用指针?这也可以通过在名称前加上星号(*)。然后就可以代替它现在指向的变量了-

    *pointer = var1 + var2;
    

    代替

    variable = var1 + var2;
    
  • 现在,使用带有一些代码的指针。现在就习惯指针的这种特性。至此,我们正在讨论指针的作用。一旦确定,就可以开始研究指针如何指向某个变量,以及如果对它们应用普通的算术运算,它们将如何反应。然后去寻找指针与数组以及指针之间的关系。

这就是我建议学习指针的全部内容。

5
Gulshan

得到一些木头小块。

在一端增加金属钩,在另一端增加金属眼。

您现在可以在可以玩的东西中创建一个链接列表。

尝试用这个物理道具进行解释。当我教一年级(新生)学生的指针时,我经常希望有这个。

小金属钩是指针,东西指着木块。

我认为任何人在玩积木后都不会得到它。

4
Tim Williscroft

当我删除所有绒毛并开始将指针视为任何其他变量而不是一些神奇的实体时(很久以前在11年级时),我的生活就变得更轻松了。我只知道3件事:

  1. 指针是一个变量,用于存储另一个变量的地址(或仅存储任何地址)。
  2. *用于获取指针变量中存储的内存位置的值。
  3. &运算符给出存储位置的地址。

剩下的就是语法糖和常识。只需使用指针编写一些简单的C程序(例如实现链接列表库)就可以了。

4
Sridhar Iyer

我真正感到震惊的解释是:

考虑一个在不同的土地上建有不同房屋的城市网格。您手里拿着一张纸。您在纸上写过:


大卫的房子,

某某街112号。


这张纸(指针变量)包含一个points到大卫家的地址。当您想告诉朋友看看大卫的凉爽房屋时,用纸价格作为房屋的参考要比在邮件中发送实际的两层楼建筑容易得多。

与真正的指针一样,当您遵循纸上的地址时,可能会遇到麻烦。大卫可能已经搬家,当您到达那里时,您只会在地面上发现一个大洞。在这种情况下,最好在David移动或至少将其更改为新地址时擦除纸上的地址。您还可能会发现自己去了地址,然后输入您认为是朋友大卫的客厅的地址,但是这次您最终进入了一个完整的陌生人游泳池。有人将您地址上的空格用于其他完全不同的地方。

2
Per Wiklander
  1. 指针可以看作是索引到数组的一般化。
    • 请考虑将一个大数组切成许多较小的,不重叠的,可变大小的数组。现在,这些较小的数组是我们通常认为的数组。那么更大的是计算机的整个内存空间。切掉较小数组的过程称为内存分配。
  2. 可以将通过某些指针链接在一起的一组结构视为 有向图
    • 每个顶点都是一个可以保存一些值的变量。
    • 有些变量是指针,每个指针可以恰好有一个传出的Edge进入其他对象。
    • 不是指针的变量将没有任何传出的Edge。他们可以有任意数量的传入Edge。
2
rwong

如果要解释指针,则必须先解释内存。我通常使用带有行和列的方格纸/方格纸执行此操作。如果“学生”了解内存,则她可以了解地址是什么。如果您有地址,则有指针。

您可以使用这种抽象。例如。将一个正方形的地址(数字)写入另一个正方形。现在从指针正方形到目标正方形绘制一个箭头。现在覆盖指针(例如增加指针)并调整箭头。在另一个方块中写一个地址,让学生画箭头...

下一步:给某些方块(如指针)起一个名字。现在您可以解释取消引用。而已。

2
EricSchaefer

我不太记得指针周围的情况,但是我根据对C样式数组的理解回溯了内存。 (即_arr[3]_与*(arr+3)相同)

出于某种原因,我发现每当遇到指针位置时,将指针视为数组都将非常有用。

2
Zaz

基本上,@ Gary Rowe引入了正确的模型。内存是一组带有地址(数字)的盒子。每个框存储一个值(数字)。

指针的想法是将一个框中的值解释为另一个框中的地址。此值用于参考到特定的框,这就是为什么它被称为参考的原因。因此dereferencing是打开所引用的框的过程。

如果v是一个变量(框),则该语句

  • v表示v的值,即给我框中的内容
  • *v表示将v的值取消引用,即给我v的值所指的框中的内容
  • &v表示参考v,即在框上给我地址

我认为它没有达到将指针引入完全不同的目的。小时候,这对我来说很难理解。似乎总是有些我从未真正理解的黑魔法,需要很多特殊字符。我第一次真正理解是当我使用没有指针算术的语言使用双向间接编写小型游戏时。这启发了我。

指针只是一个解释问题。我认为解释一下使事情变得容易得多。如果显示一个具有10个变量的内存的简单示例,则指针算术是极其简单和直观的操作。

2
back2dos

也许只有我一个人,但我可以比喻很好地工作。因此,假设您有一个朋友(函数/类)“ Foo”,但由于某种原因,他想让其他人(函数/类不同)“ Bar”与您联系。 “ Foo”可以带您去看看“ Bar”,但这不方便,将所有这些生物(实例)移动到四周。但是,“ Foo”可以向“ Bar”发送您的电话号码(指针)。这样,无论您身在何处,“ Foo”都知道如何联系您而无需找到您。

并且,假设“ Bar”有一个熟人“ Baz”,他也想与您联系。但是您可以保护自己的电话号码,并且不希望所有人都拥有,“ Baz”可以呼叫“ Bar”(电话作为指针),然后后者可以将呼叫转发给您(另一个指针)。依此类推,直到“巴兹”的朋友和朋友的朋友。

2
Hugo

如果您学习过汇编语言和/或计算机体系结构,则指针会更有意义way。我认为,如果我教C类,那么我将从构架的几个星期开始,以解释内存模型和处理器实际执行的指令种类。

2
Barry Brown

我的“啊哈!”本教程中出现的时刻:

C语言中的指针和数组教程

确切地说,它出现在本章中: 第3章:指针和字符串

更准确地说,它带有以下句子:

传递给puts()的参数是一个指针,即一个指针的值(因为C中的所有参数都按值传递),而指针的值就是它指向的地址,或者简单地是一个地址。

当我读到这篇文章时,乌云散开,天使们吹响了号角声。

因为,您看到的是,在此之前我读过的每本C教程或书都断言C可以通过值或引用来传递邪恶的谎言。事实是C总是按值传递,但是有时传递的值恰好是一个地址。在该方法中,该地址是一个副本,就像复制传入的int一样。副本是not指针指向的值。因此,通过使用方法中的指针,您可以访问原始值并进行更改。

我从未成为C程序员,但后来成为.NET程序员,并且对象和对象引用的工作方式相同。对对象的引用按值传递(并因此被复制),但对象本身未复制。我与许多不了解这一点的程序员合作,因为他们从未学习过指针。

2
Kyralessa

指针是一个便签,可以告诉您有用的内容在哪里。它包含事物的位置,并告诉您事物的大小(无论如何,在C中)。因此,双指针就像一个便签,上面写着“冰箱里有六包”。您必须实际得到六支装才能确定是可口可乐还是百威啤酒。

1
philosodad

http://cslibrary.stanford.edu/

该站点提供了很棒的教程,用于学习指针和内存管理。

我建议您逐步了解该站点上提供的指针基础知识,指针和内存。您还可以查看链接上给出的链接列表问题,以进一步加强指针概念。

1
deovrat singh

给出代码:

int v=42; //声明并初始化一个简单变量

int *p = &v; //创建指向变量v的点p

下面可以说上面的代码:

int * p //“ int指针p” ...这就是您如何声明一个指向int类型变量的指针

*p //“由p指向” ...即p指向的数据,与v相同。

&v //“变量v的地址” ...这代表p的文字值

1
zener

解释指针的关键是确保您要向其解释的人员已经了解内存的概念。如果他们真正了解它的底层知识,那将是不错的选择,因为他们认为内存是一个庞大的数组,并且了解您可以通过其索引位置访问数组中的任何位置就足够了。

下一步,具有传递索引位置而不是复制整个内存的概念对大多数人来说都是有意义的。这足以使大多数人理解为什么指针有用。

理解指针的最后一步是解释如何将内存索引位置作为参数传递给该方法,以存储所有数据存储位置的索引位置。我发现对于某些人来说这可能太过分了。

一旦有人掌握了这些基本步骤,他们便可以直接理解,可以无限期地链接指针,只要您跟踪需要多少次查看地址即可找到实际的数据对象。

一旦有人掌握了指针,他们必须迅速掌握的下一件事就是堆内存和堆栈内存之间的区别,以及为什么在方法外传递指向堆栈内存的指针很危险。

1
Michael Shaw

诀窍是要解释事物的位置和事物本身不一样,就像管道的图片 不是管道 。当您移动事物时,其位置会改变。该位置仍然存在,可以将其他东西放在那里。

1
sal

假设您至少已经从表面上理解了数组,那么我对指针的最佳解释是:

想象一下计算机中的所有内存(如果想更精确的话,可以在进程中使用地址空间)作为一个巨大的字节数组。指针只是该数组的索引。因此,指针只是一种特殊的整数。

了解C和Assembly编码器可以通过将指针视为整数来完成的所有技巧,以及这种区别在Assembly Language级别上纯粹是惯例的,这有助于我巩固这一理解。

0
dsimcha

当我上大学时,我的教授有一些非常整齐的PowerPoint幻灯片,这些幻灯片将一个点单独描述为一个单独的变量,并带有指向内存位置的箭头(表示为数组),当我们做“链表”时,他会一步一步地完成分步显示箭头何时更改,指针何时取消引用等...,在几分钟之内就无法理解它。这个概念本身确实很容易,但是正确地执行它或将其应用到实际程序中需要更多的实践。

0
chiurox

在此之前,我将解释在编程中“所有事物都使用内存”以及内存中的(静态)变量分配。我还将解释什么是内存地址,以及内存空间,内存地址和变量之间的关系。

最后,我将解释整数数据类型和变量,字符串数据类型和变量...等等,直到解释存在一种特殊的数据类型来存储内存地址,该地址的空值如0 o“”,称为null

最后,通过指针的使用来动态分配变量。

0
umlcat

我记得一本书“ C Puzzles”或类似的书,我读这本书纯粹是因为它是图书馆中与编程/计算机相关的少数书籍之一,我对C的理解是基本的。它对您产生了C表示,并要求爆炸它,变得越来越复杂。

0
peterchen