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

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


当前回答

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

int *mypointer;

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

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

int* mypointer;

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

其他回答

在C/ c++语言中,指针为什么是许多新、甚至老大学生困惑的主要因素?

一个值的占位符的概念——变量——映射到我们在学校教的东西——代数。如果不理解内存在计算机中是如何物理布局的,就无法画出一个现有的并行图,而且没有人会考虑这种事情,直到他们处理低级别的事情——在C/ c++ /字节通信级别。

有没有什么工具或思维过程可以帮助你理解指针在变量、函数和级别之外是如何工作的?

地址框。我记得当我学习在微型计算机上编程BASIC时,有一些漂亮的书,里面有游戏,有时你必须在特定的地址中插入值。他们有一张图片,上面有一堆盒子,标有0、1、2……它解释说,只有一个小的东西(一个字节)可以装在这些盒子里,而它们有很多——一些计算机有多达65535!他们紧挨着,都有一个地址。

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

为了演习?创建一个结构体:

struct {
char a;
char b;
char c;
char d;
} mystruct;
mystruct.a = 'r';
mystruct.b = 's';
mystruct.c = 't';
mystruct.d = 'u';

char* my_pointer;
my_pointer = &mystruct.b;
cout << 'Start: my_pointer = ' << *my_pointer << endl;
my_pointer++;
cout << 'After: my_pointer = ' << *my_pointer << endl;
my_pointer = &mystruct.a;
cout << 'Then: my_pointer = ' << *my_pointer << endl;
my_pointer = my_pointer + 3;
cout << 'End: my_pointer = ' << *my_pointer << endl;

与上面的例子相同,除了在C中:

// Same example as above, except in C:
struct {
    char a;
    char b;
    char c;
    char d;
} mystruct;

mystruct.a = 'r';
mystruct.b = 's';
mystruct.c = 't';
mystruct.d = 'u';

char* my_pointer;
my_pointer = &mystruct.b;

printf("Start: my_pointer = %c\n", *my_pointer);
my_pointer++;
printf("After: my_pointer = %c\n", *my_pointer);
my_pointer = &mystruct.a;
printf("Then: my_pointer = %c\n", *my_pointer);
my_pointer = my_pointer + 3;
printf("End: my_pointer = %c\n", *my_pointer);

输出:

Start: my_pointer = s
After: my_pointer = t
Then: my_pointer = r
End: my_pointer = u

也许这通过例子解释了一些基础知识?

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

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

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

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

int *mypointer;

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

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

int* mypointer;

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

我喜欢家庭地址的比喻,但我一直认为地址是邮箱本身。通过这种方式,您可以可视化解除指针引用(打开邮箱)的概念。

例如在一个链表下面: 1)论文开头写上地址 2)去纸上的地址 3)打开邮箱,找到一张新纸,上面写着下一个地址

在线性链表中,最后一个邮箱中没有任何内容(列表的末尾)。在循环链表中,最后一个邮箱具有其中第一个邮箱的地址。

请注意,第3步是发生解引用的地方,当地址无效时,您将崩溃或出错。假设你可以走到一个无效地址的邮箱前,想象那里有一个黑洞或什么东西,把世界翻个底朝天:)

我不认为指针本身令人困惑。大多数人都能理解这个概念。现在你能想到多少个指针或者你能适应多少个间接层次。不需要太多就能让人崩溃。它们可能会被程序中的错误意外更改,这也会使它们在代码中出错时很难调试。