年轻人需要学习指针概念吗?


89

为什么C大师Dennis Ritchie会在C中引入指针?以及为什么其他编程语言(例如VB.NET或Java或C#)消除了它们?我在Google中找到了一些要点,我也想听听您的评论。他们为什么要消除现代语言中的指针概念?

人们说C是基本语言,而指针是使C强大而又出众且使C仍能与更多现代语言竞争的概念。那么为什么他们要用更现代的语言消除指针呢?

您认为指针知识对于新程序员仍然重要吗?如今,人们正在使用VB.NET或Java,它们支持比C更高级的功能(并且不使用任何指针概念),而我现在看到的许多人(我的朋友)选择这些语言而忽略了C,因为它们支持高级功能。我告诉他们以C开头。他们说,当您在VB.NET或Java中进行高级的操作(在C中无法实现)时,学习指针的概念很浪费。

你怎么看?

更新时间

我在Google上读到的评论是:

  1. 较早的计算机速度太慢且未优化。

  2. 使用指针可以直接访问地址,这样可以节省时间,而不是在函数调用中复制它。

  3. 使用指针的安全性要差得多,这就是Java和C#不包含指针的原因。

这些以及更多我发现的东西。我仍然需要一些有价值的答案。这将不胜感激。


52
Java没有指针?这不是真的。基本上,Java中的每个对象引用都是一个指针。
quant_dev

20
quant_dev的意思是Java充满了透明使用的指针,而程序员无法显式使用它们。
sakisk 2011年

9
这是来自Joel Spolsky的相关文章... joelonsoftware.com/articles/fog0000000319.html
Joe Internet,

11
“为什么C大师Dennis Ritchie在c语言中引入了指针?” 指针在c中引入,它们直接来自汇编实践(包括名称)。
dmckee 2011年

14
@quaint_dev:好吧,Java确实没有指针。引用不能完成指针可以做的所有事情,因此,尝试以引用的方式理解指针并不是要走的路(这是很多学习C或C ++的程序员所犯的错误)。指针可以算术。参考不能。(每次我被迫使用Java时,这种限制确实会发散)
Billy ONeal

Answers:


128

那时,开发人员与金属的距离越来越近。C本质上是汇编的更高层次的替代品,它几乎与您所能获得的硬件几乎一样,因此很自然地需要指针来有效地解决编码问题。但是,指针是锋利的工具,如果使用不当可能会造成很大的损坏。此外,直接使用指针可以解决许多安全问题,而这在当时并不是问题(在1970年,互联网由几所大学中的几十台机器组成,甚至没有这样的名称) ...),但此后变得越来越重要。因此,如今有意识地设计了高级语言以避免原始内存指针。

说“用C无法在VB.Net或Java中完成高级的事情”表示的观点非常有限,至少可以这样说:-)

首先,所有这些语言(甚至汇编语言)都是图灵完整的,因此从理论上讲,用一种语言可能发生的一切,都将是可能的。只需考虑一下一段VB.Net或Java代码的编译和执行会发生什么:最终,它会被翻译成(或映射到)机器代码,因为那是机器唯一能理解的东西。在像C和C ++这样的编译语言中,您实际上可以将等同于原始高级源代码的完整机器代码作为一个或多个可执行文件/库。在基于VM的语言中,获取程序的整个等效机器代码表示形式比较棘手(甚至可能无法实现),但最终仍会在运行时系统和JIT的深层隐蔽中找到某个地方。

现在,当然,在某种特定语言下某种解决方案是否可行是一个完全不同的问题。没有明智的开发人员会开始以汇编形式编写Web应用程序:-)但是请记住,大多数或所有这些高级语言都建立在大量的运行时和类库代码的基础上,其中很大一部分用较低级别的语言(通常用C语言)实现的。

因此,要解决这个问题,

您认为对年轻人的指点知识重要吗?

指针背后的概念是间接的。这是一个非常重要的概念,恕我直言,每个优秀的程序员都应在一定程度上掌握它。即使有人只使用高级语言,间接和引用仍然很重要。不理解这一点意味着无法使用一整套非常有效的工具,从长远来看会严重限制一个人的问题解决能力。

因此,我的答案是肯定的,如果您想成为一名真正的优秀程序员,那么您还必须了解指针(以及递归-这是刚起步的开发人员的另一个典型绊脚石)。您可能不需要从头开始-我认为C作为当今的第一语言不是最佳的。但是到某个时候,人们应该熟悉间接。没有它,我们将永远无法理解我们正在使用的工具,库和框架是如何工作的。不了解其工具工作原理的工匠是非常有限的。相当公平,人们也可以使用高级编程语言来掌握它。一个很好的石蕊测试是正确地实现一个双向链表-如果您可以用自己喜欢的语言来做,则可以声称您对间接的理解足够好。

但是,如果没有别的事情,我们应该这样做,以尊重那些设法使用他们曾经拥有的荒谬简单工具(与我们现在拥有的工具相比)来构建令人难以置信的东西的老程序员。我们都站在巨人的肩膀上,承认这一点对我们有好处,而不是假装我们自己就是巨人。


5
这是一个很好的答案,但并不能真正回答以下问题:“年轻人需要学习指针概念吗?”
猎鹰

11
+1好答案。但是,我会删除图灵完整性的参数-对于实际编程,这是一个红色的鲱鱼,稍后您也将注意到。这是可计算性理论,即完全固化仅意味着在(对于许多语言而言,是无限的)潜在程序空间中存在一个实现相同算法的程序,而不是实际上可行还是人为可行的程序。只需指出最后所有机器代码就可以证明这一点,而无需植入愚蠢的“我可以用一种语言来做所有事情,因为它们都是一样的,哈哈!” 种子。

5
+1表示“而且不了解其工具工作原理的工匠是非常有限的。”
quick_now 2011年

6
同样,不了解指针(和扩展引用)的机制也意味着您不了解浅/深数据结构复制的概念,这可能会导致严重的难以跟踪的错误。即使使用“现代”高级语言。
马夫里克

1
C被设计为Unix的便携式汇编程序,即接近金属的汇编程序。

39

我认为您需要有所不同。

Java和其他高级语言没有删除指针。他们所做的是删除普通指针算法。

实际上,Java仍然允许使用受保护受限制的指针算法:数组访问。在普通的C语言中,数组访问只不过是取消引用。如果您愿意清楚地交流您在做什么,那是一种不同的表示法,一种语法糖。
仍然array[index]等同于*(array+index)。因此,index[array]尽管我认为某些C编译器可能会警告您,但它也等同于此。
作为推论,pointer[0]等效于*pointer。这仅仅是因为“指向数组的指针”是数组的第一个条目的地址,而后续元素的地址是通过添加索引来计算的。

在Java中,不再存在普通指针算术(引用和取消引用)。但是,存在指针。他们称它们为引用,但这并不会改变它的含义。数组访问仍然是完全一样的:查看地址,添加索引并使用该内存位置。但是,在Java中,它将检查该索引是否在您最初分配的数组的范围内。如果没有,它将抛出异常。

现在,Java方法的优势在于,您无需编写代码,只需盲目地将任意字节写入任意内存位置。这将提高安全性,同时也提高了安全性,因为如果您无法检查缓冲区溢出等,运行时将为您完成。

这样做的缺点是它的功能不那么强大。可以在C语言中进行内存安全编程。不可能从Java的速度和不安全编程的可能性中受益。

实际上,指针或指针算法并不困难。通常只是以复杂的方式解释它们,而所有指针都是一个巨型数组(您的内存空间)的索引,所有引用一个值的工作都是为您提供在哪里可以找到它的索引,所有解引用的工作就是查找给定索引的值。(这只是简化了一点,因为它没有考虑值在内存中的大小取决于其类型的不同。但这只是一个偶然的细节,而不是实际概念的一部分)

恕我直言,我们工作中的每个人都应该能够理解这一点,否则他们将进入错误的领域。


13
+1 Java和C#仍然具有指针,当然还有NullPointerExceptions
jk。

5
还要注意,随着垃圾收集器的移动,引用可能会随着时间指向不同的区域。指针通常是静态的。

3
+1:这个!而且,我认为关于指针(一般而言)有两点要把握:间接(在C,C#,Java等情况下发生)和指针算术(在Java中不会以相同的方式发生)。在我看来,这两个都是重要的概念,对于初学者来说,它们都是主要的绊脚石。但是,它们不应该混淆:如果没有指针算法,间接调用就可能发生。
约阿希姆·绍尔

2
实际上,back2dos第一次是正确的,因为(array + index)已经考虑了对象的大小(以C表示)。
Matthew Flaschen

4
@Cyber​​Skull,答案是在语法上等同于array[index],那就是*(array+index)。如果要显示编译器如何在内部执行操作,则可以显式地讨论字节或提供程序集。
马修·弗莱申

24

指针的概念在一般的计算机编程知识中很重要。理解该概念对于任何语言的程序员或程序员都是有益的,即使该语言不直接支持它也是如此。

指针在数据结构(链接列表)和数据库设计(外键)中有其用途。

诸如VB和C#之类的语言可以通过“引用”将数据传递给方法,这些方法可以认为是一种指针。

了解数据在内存中的分配位置(堆栈还是堆)对于提高算法效率仍然很重要。

我认为,学习基本权利很重要。


我发现一般概念会有所帮助,但我从未发现需要指针的情况(当然,我主要使用Java和PHP)。唯一的例子我的C ++课程曾经想出了指针,用它们来创建中存在的任何高级编程语言,开始用类似列表和字典更复杂的数据结构..
奔Brocka

2
您在某种程度上是正确的,但是当您将数据传递给方法时,在某些情况下,您很可能会将指针传递给变量。但是,指针的概念是有用的(在我看来),无论其在软件语言中的实现如何。
NoChance 2011年

1
@SirTapTap:这是因为,如果您通过某种课程学习了C ++,他们就会教您C ++。不是使用C ++的最佳方法。指针算术通常会被遮盖,因为您可以对C ++有所了解而又不知道。但是,即使迭代通用集合之类的事情也可以通过真实/惯用的C ++中的指针来完成。(因为它是标准模板库工作方式的基础)
Billy ONeal

@BillyONeal指针几乎完成了一半的课程,实际上,我仍然没有找到作为程序员的(智能)指针的实际用途,因为我从不需要做任何事情来直接控制内存。当然,总会有课程教学效果不佳的可能性,这并不是我的最爱。
Ben Brocka

1
@SirTapTap:实际使用:STL中的每个集合和算法。std::sortstd::partitionstd::find,等他们与指针工作,他们与像指针(迭代器)对象。他们可以处理所有常规收藏;链表,动态数组,deques,树或任何其他类型的用户定义的集合。没有指针,您将无法实现这种抽象。
Billy ONeal

19

是的,是的,是的,是的,是的!!!

如果您不了解基础知识,您将永远无法解决您遇到的真正困难,奇怪,困难和复杂的问题。

而且,如果您确实非常了解基本知识,那么您将在就业市场上更具市场竞争力。


我曾经和一位已经编程十年的家伙打交道,却不知道指针是如何工作的。我(大三)在白板上花了几个小时来教育他。那使我大开眼界。他对这么多基本的东西没有想法。

尽可能多地了解。


但是基础是什么?汇编,二进制代码?
SiberianGuy

5
尽管您的“尽可能多地了解”的一般观点是合理的,但我会质疑这样一个想法,即您将“永远无法解决您遇到的真正困难,奇怪,困难和复杂的问题”。不懂指针。这某种程度上意味着可以使用这些“魔术”指针解决所有困难的问题,事实并非如此。指针之间的概念很有用,但是对于许多编程领域而言,它们并不是直接必需的。
Dan Diplo

4
@Idsa:不,甚至更基本的是,如今许多程序员甚至都不知道晶体管和逻辑门如何在粘性芯片中工作,他们当然应该知道电子如何运动以及量子不确定性对小型化的影响;我什至还没有开始研究庸俗,立顿和野牛!打the野牛粒子!
Lie Ryan

2
基础知识....诸如如何存储东西之类的东西。字节,单词,有符号和无符号的工作方式之间的区别。指针如何工作。什么字符 事物是如何用ASCII编码的(现在是Unicode)。仅使用简单结构如何在内存中创建链接列表。字符串如何真正起作用。从这些小事情中,更大的事情发展起来。
quick_now 2011年

5
尽可能多地了解是一个很好的原则,但我认为您在骑马之前就已经掌握了手推车。优秀的开发人员会尽一切努力学习,因为他们是优秀的开发人员。对知识的渴望是优秀开发人员的特征。这不是优秀开发人员的原因。尽可能多地去学习并不能使您成为一名优秀的开发人员。它将使您成为步行百科全书,仅此而已。如果您是一名优秀的开发人员,那么您可以应用所获得的知识来解决问题。但是,如果您还不是一个好的开发人员,那么所学的知识将为您带来很多好处。
corsiKa 2011年

18

是的,理解很重要。

几个月前,我正在用C#编程,我想复制一个列表。当然我所做的是NewList = OldList;然后开始进行修改NewList。当我尝试打印两个列表时,它们都是相同的,因为它们NewList只是一个指针,OldList而不是副本,因此我实际上一直在进行更改OldList。我花了很长时间才弄清楚一个人,但是我的一些同学并没有那么快,所以必须解释为什么会这样。

例:

List<int> a = new List<int>();
a.Add(2);
a.Add(9);
a.Add(8);
a.Add(1);
List<int> b = new List<int>();
b = a; //Does not make a copy, b is just a synonym!
b.Sort();
for (int i = 0; i < a.Count; i++)
{
    Console.WriteLine("a: " + a[i] + " b: " + b[i]);
}

当然,结果是这样的:

a: 1 b: 1
a: 2 b: 2
a: 8 b: 8
a: 9 b: 9

知道如何使用它们并不重要,但了解它们至关重要!


2
相反,为什么要使用它们以及何时使用它们才是最重要的:)
niko

5
NewList只是一个指向OldList -更确切地说,两个NewListOldList只是指针,指的是同一List对象。
彼得Török

了解您为之创建的新列表b不再具有对它的引用,现在已成为垃圾,这也很重要。
TMN 2012年

14

指向概念!=指向算术!=指向语法

如果您需要(并且确实需要)了解深层/浅层副本,按引用传递/按值传递等,则前两者始终很重要。仅当您的语言允许您使用它们时,后两者才重要。


1
如今,您只需要了解引用的基本概念,而不必了解指针语法/数学。那天我在C中学习了指针(带有算术和语法)。我现在使用的语言不会处理允许您执行不安全操作的C样式指针。可以理解为什么在python中a=[1,2]; b=a; a.append(3)a并且b都将引用相同的对象[1,2,3]而又不知道C之类的东西i,所以数组的th元素可以被arr[i]i[arr]都引用*(arr+i)。我更喜欢这种语言不i[arr]被使用。
jimbob博士2011年

其他两个只有在您的语言允许您使用它们的情况下才重要。 ”-该句子带有自己的自毁对象。顾名思义,按您的语言是极不可能与明天使用的语言相同。明天您可能会遇到启用指针的语言。底线?更好的人现在就可以一劳永逸地掌握它。这并不难,但是值得。
JensG 2014年

14

为什么C大师Dennis Ritchie会在C中引入指针?

因为指针是一种非常强大的机制,可以通过多种方式使用。

为何其他编程语言(如VB.NET或Java或C#)消除了它们?

因为指针是一种非常危险的机制,可以通过多种方式滥用。

我认为程序员应该学习指针,但是从教育的角度来看,尽早引入它们是不明智的。原因是它们被用于许多不同的目的,作为初学者很难说为什么在特定情况下要使用指针。

这是一个不完整的列表,这些指针用于:

  • 动态分配(new T
  • 递归数据结构(struct T { T* next; /* ... */ };
  • 数组上的迭代器(for (T* p = &a[0]; p != &a[0] + n; ++p) { ... }
  • 共享访问对象(T* new_pointer = existing_pointer;
  • 亚型多态性(T* pointer_to_base = pointer_to_derived;
  • 按引用的旧电话(mutate(&object);
  • 可选类型(if (p) { /* ... */ }

请注意,对所有这些概念使用单一机制,既可以证明经验丰富的程序员的能力和优雅,也可以为刚接触编程的人带来巨大的困惑。


为什么C大师Dennis Ritchie会在C语言中引入指针?因为指针是一种非常强大的机制,可以通过多种方式使用。” -我不知道一个事实,但是我想这与包装成C语言的机器指令和C的前身有关。汇编程序程序员习惯于在指针中进行思考,因此本来可以如果他没有使用这些众所周知的强大机制,那将是一个惊喜。对于1978年甚至1960年代,任何其他事情都不会太遥远。
JensG 2014年

12

为什么?您可以使用Forms Designer和代码生成器编写一个庞大的系统。这还不够吗?(讽刺)

如今,认真的说来,指针在许多领域中都不是编程的关键部分,但是它们使人们能够了解内部原理。而且,如果我们没有人了解内部结构是如何工作的,那么就有可能将SQL2020,Windows 15和Linux 20.04编写为运行30层抽象层的垃圾收集虚拟机,并使用JavaScript通过IDE生成代码。

这绝对不是我想要看到的。

所以是的,他们一定一定要!


2
良好的幽默感!+1并完全同意。
heltonbiker 2011年

7

Java和C#都没有消除指针,它们具有几乎相同的引用。消除的是指针算法,可以在入门课程中将其省略。
没有指针或引用的概念就不可能完成不平凡的应用程序,因此值得教导(没有它们就无法进行动态内存分配)。

考虑一下C ++和Java中的以下内容,我想在C#中并
aClass *x = new aClass();
aClass x = new aClass();
没有太大区别:指针和引用之间并没有太大区别,对吗?
除非必要以及在使用高级模型进行编程时,否则应避免使用指针算术,因此那里没有太多问题。


6

专业的程序员应该掌握指针。

想要了解编程的人应该了解它的存在和含义,但不一定要使用它们。

想要通过编程解决个人问题的人(像我一样,使用许多Python脚本)完全可以忽略它们。

好吧,这是我的意见...; o)


3

可变地址指针是更广义的间接概念的特定情况。在大多数(所有?)现代语言中,都在许多构造中使用了间接寻址,例如委托和回调。了解间接的概念使您知道何时以及如何最佳地使用这些工具。


3

绝对是的!每个编程人员都需要了解指针和间接性。

指针是所有语言如何完成大量数据访问的方式。指针是所有微处理器的硬件功能。诸如Java,VB和C#之类的高级语言从本质上限制了使用语言的用户对带有引用的指针的直接访问。引用通过语言的内存管理方案来引用对象(例如,可以是带有元数据的指针或仅是内存表的数字)。

了解指针如何工作的基本了解计算机是如何工作的。指针也比引用更灵活,功能更强大。

例如,数组从索引0开始的原因是因为数组实际上是指针算术的简写形式。在不了解指针如何工作的情况下,许多新手程序员并没有获得数组。

int a, foo[10];
foo[2] = a;

指针算法的第二行是:

*(foo + sizeof(int) * 2) = a;

如果不了解指针,就无法理解内存管理,堆栈,堆甚至数组!此外,还需要了解指针和取消引用以了解如何传递函数和对象。

TL:DR:了解指针是理解计算机实际工作的基础


2

我认为可以归结为这样一个事实,即由于程序员对运行的直接硬件的处理较少,因此处理指针的需求逐渐减少。例如,以完全适合专用硬件具有的640字节内存模块序列的方式分配链表数据结构。

手动处理指针容易出错(导致内存泄漏和可利用的代码),并且花费时间才能正确处理。因此,Java和C#等现在都通过它们的虚拟机(VM)为您管理内存和指针。尽管虚拟机在不断改进,但这可能比使用原始C / C ++效率低。

C(和C ++)仍然是广泛使用的语言,尤其是在高性能计算,游戏和嵌入式硬件领域。我个人很感激我了解了指针,因为到Java引用的转换(类似于指针的概念)非常容易,当我看到我的第一个NullPointerException(它应该真正称为NullReferenceException,但我离题)时,我并没有迷路。

我建议您学习指针的概念,因为它们仍然是许多数据结构等的基础。然后继续选择您喜欢使用的语言,知道如果出现NPE之类的东西,您就知道真正的情况。 。


0

这是客观事实:

有些语言支持直接内存访问(指针),有些则不支持。每种情况都有充分的理由。

  1. 就像在这里所说的那样,在C时代,自动内存管理并不像今天这样复杂。无论如何,人们已经习惯了。那时,优秀的程序员比我们这一代(我21岁)对计算机程序有更深入的了解。他们在大型机上一直使用打孔卡和等待几天的编译时间。他们可能知道为什么代码中的每一点都存在。

  2. 像C这样的语言的明显优点是,它们使您可以更好地控制程序。这些天您什么时候真正需要它?仅在创建基础结构应用程序(例如与OS相关的程序和运行时环境)时。如果您只想开发良好,快速,健壮和可靠的软件,那么自动内存管理通常是您更好的选择。

  3. 事实是,在软件开发过程中,直接内存访问已被滥用。人们一直在创建程序,这些程序会泄漏内存,实际上由于冗余的内存分配而速度较慢(在C语言中,为每个分配分配扩展进程的虚拟内存空间既容易又常见)。

  4. 如今,虚拟机/运行时在分配和释放内存方面比99%的程序员做得更好。最重要的是,它们使您在想要的程序流中具有更大的灵活性,因为(通常)您没有在适当的时间和地点释放分配的内存。

  5. 至于知识。我认为程序员知道如何实现编程环境是令人钦佩的。不一定要最小的细节,而是全局。

我认为了解指针的工作原理(至少)很有趣。与知道如何实现多态性相同。您的过程从哪里获取内存以及如何获取内存。这些都是我个人一直感兴趣的东西。老实说,他们使我成为了一名更好的程序员,但是对于任何想成为一名优秀程序员的人来说,它们都不是教育上的必需品。在任何一种情况下,了解更多信息通常会使您的工作更好

  1. 我的看法是,如果只需要用Java或C#或类似的方式创建应用程序,那么您就需要专注于适当的设计和实现技术。可测试的代码,简洁的代码,灵活的代码。以该顺序。

因为即使您不了解所有细微的细节,做某事的人也可以将您创建的内容更改为性能更好的内容。一旦有了适当,干净和可测试的设计(通常是大多数工作),这通常就不是一件容易的事。

如果我是一名面试官,希望聘请某人进行高级语言申请,那将是我最感兴趣的事情。

低水平的知识是一种奖励。这对于调试和偶尔创建稍微更好的解决方案非常有用。专业地使您成为一个有趣的人。它可以使您在工作场所受到尊重。

但是在当今世界,这不是神圣的要求。


-1

对于高级OO语言中的大多数实践目的而言,了解引用就足够了,您实际上并不需要了解这些语言如何如何根据指针来实现引用。

我认为有很多功能和现代的多范式方法要比能够执行花哨的指针算法高得多,要写出第1000个优化的字符串复制函数,其性能可能比标准lib的String.copy差。

我建议先学习更多不同的高级概念,然后再尝试学习不同设计的语言以拓宽您的视野,然后再尝试专门研究接近硬件的内容。

我经常看到尝试微优化Web servlet或类似代码以获得5%的收益的完全失败的尝试,而缓存(内存),SQL优化或仅通过Web服务器配置调整就可以毫不费力地产生100%或更多的收益。在大多数情况下,摆弄指针是过早的优化


-1

当然,如果您确实想成为一名优秀的程序员,我们需要有一个彻底的指针概念。指针概念的原因是直接获得您的价值,在时间限制下,它变得越来越高效。

同样,现在,考虑到移动应用程序的内存非常有限,我们需要非常谨慎地使用它,以便其操作能够在用户响应时非常快...为此,我们需要直接引用该值...

考虑一下Apple的设备或Objective C语言,它仅与指针概念一起使用。在目标C中声明的所有变量都具有Pointer。您需要浏览Objective C的Wiki


如今的移动应用程序具有比C设想的某些数据中心更多的可用内存。许多移动应用程序都是用Java或完全html + javascript编写的,所有这些都没有指针(确实具有参考)。非常专业的程序员中只有很少一部分能看到底层的OS层。
尔根·斯特罗贝尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.