为什么C++使用指针?

14

C++为什么需要并使用指针?我知道它们为语言增添了强大的功能,但对于初学者来说,这使得理解变得更加困难。像F#、Java、Ruby、Python、Lua等语言在没有指针的情况下运行良好,并且它们都很强大。


4
http://en.wikipedia.org/wiki/History_of_programming_languages - OscarRyz
2
这是一个开始了解编程语言的一般情况。您正在比较C++与C#和其他更新的编程语言。这种背景有助于理解为什么C++使用指针。 - OscarRyz
3
如果你正确地使用 strcpy,那么它是最快速的复制字符串方式。如果运行时性能很重要,C/C++ 代码几乎等同于汇编代码,但写起来会少很多痛苦。虽然在今天的处理器上看起来似乎不那么重要,但在 80 年代的 8 MHz 处理器上绝对非常重要。;-) - Treb
2
@RCIX,你还不明白为什么在某些情况下你会选择更强大的语言吗?假设我正在为现有音乐程序编写混响插件。调用程序告诉我音频缓冲区在内存中的位置。如果我使用Java,我能读取缓冲区中的字节并替换它们吗?我的Java程序甚至能编译成音乐程序想要的dll文件吗?也许这是可能的,但这并不简单。我知道如何在汇编和C中实现它。但我不知道如何在Java中实现。(注:你可以使用包装器来实现。但我敢打赌包装器是用C++编写的。) - Nosredna
2
这个问题似乎不适合讨论,因为它询问的是设计动机,而不是具体问题。答案只能是“因为标准规定如此”。 - bitmask
显示剩余9条评论
13个回答

56

你提到的所有其他语言(至少还有Java),虽然非常有用和可用,但是不像C ++(和C)允许您接近机器:简单地说,所有这些语言都会对您施加更高级别的抽象...这可能大多数情况下都可以接受,但将偶尔妨碍您。

C ++是一种更大更复杂的语言,因为它允许在非常低的抽象级别(非常接近机器)和相当高的抽象级别(接近您提到的许多语言)之间进行编程,而且在同一语言内,事实上在同一源文件内。

初学者最好远离这种强大且(不可避免地)复杂的能力——但并非每个程序员都是初学者,并且并非每一位代码都需要处于具有“保护可怜的家伙免受伤害”的主要设计目标的环境中!-)


7
对于这种强大而复杂的工具,建议初学者远离……不过初学者通常也会被引导去学习提供了几乎同样难度概念的语言,即使这些语言可以通过指针实现相似的功能。 - Jimmy
5
在我看来,现在帕斯卡语言已经过时了,初学者最好从Python或Ruby开始(如果你在教学上属于“让他们尽早轻松成功”的阵营),或者选择D、C#或Java(对于稍微更有严谨要求的人),或者Haskell或SML(如果他们是数学专业的学生)[或者其他一些函数式语言]。我一直钟爱Scheme,但我理解为什么MIT会选择Python而不是Scheme作为初学者的编程语言。 - Alex Martelli
10
通常当我看到Alex回答一个问题时,我会阅读它以学习比我所能提供的更好的答案。虽然我不是C++专家,但我认为Alex的评论基于他们所说的内容是有根据的,但在我看来并未对问题给出正确的答案。答案很简单,就像bluebrother已经说的那样:从一开始,Stroustrup就把让C++成为C的超集作为高优先级,因此由于C具有指针,C++必须拥有它们。去年秋天,Stroustrup做了这个演讲:http://www.dcacm.org/archives/Lists/2008%20Events/Attachments/6/stroustrup_dc_acm_50th.pdf - PTBNL
1
我认为有很多不同的学习方法。我始终记得指针是一个非常直接、因此非常易于理解的概念,远比任何类、对象、引用和实例都不那么晦涩。虽然基本工具让你以非常基础的方式摸索,但它们也教授了非常基本(且有用)的概念,有助于理解更复杂的东西。因此,我倾向于说“从指针开始”,因为它使概念(和引用的使用)更容易理解。当然,前提是您有足够的学习时间。 - Don Johe
2
我在大学学习Pascal时学会了指针,然后在下一门C语言实验课中使用了它。接着在工作中(我每次都感谢我的前任老板!)我学会了C++。第二年,在大学里他们把教学语言从Pascal改成了Java...我很高兴自己比那届早出生了一年 :) - Patrizio Rullo

26

也许C++并不适合初学者。

指针已经存在很长时间了,它们在Pascal和C语言中就有了。当C++出现时,如果没有指针,它可能会一开始就失败。


31
+1,大声说Amen!--为什么每件事都必须适合初学者?! - Alex Martelli
14
指针有什么难理解的?即使是现在,程序员也学习到指令和数据存储在可寻址位置的内存中,对吧?指针只是指出了这个位置在哪里。难在哪里呢?我比学C语言还早学汇编语言,或许汇编语言程序员在学习C指针时会更有优势。 - Nosredna
11
@RCIX. 我们不应该有太空飞机。它们对于初学者来说太难驾驶了。 - Nosredna
2
说实话,C++并不难。如果你写的代码“几乎在你最意想不到的时候就会崩溃”,那更多地反映了你糟糕的编码能力,而不是这门语言的问题。巧匠不会抱怨自己的工具。 - Bob Somers
4
抱歉,但我真的不信任那些经过一点学习仍无法理解指针概念的程序员的能力。这并不是一个很难的概念。 - Ed S.
显示剩余6条评论

17

我还没有看到的一个原因:

C++ 的设计目标是与 C 兼容,因此简单来说,C++ 是 C 的超集(虽然不是100%正确,但几乎是这样)。由于 C 具有指针(并且由于其低级别的特性需要它们),C++ 也需要支持它们。


1
为了让系统程序员愿意使用,C++需要能够完成C语言所能做的一切。True. - Nosredna

12

C#有指针,没有它们我就不可能很好地完成工作。这完全取决于你在做什么,学习指针对开发人员非常有益。问题不是为什么使用它们,而是何时使用它们。


11
很多好的答案在这里,但是没有很多好的例子来说明为什么需要它,或者为什么有时候称C为“可移植汇编语言”。
在机器的最低抽象级别上,有大量硬件功能通过内存范围访问。这些内存地址通常具有各种类型的硬件标准化。
例如,当x86计算机首次启动并加载BIOS和启动引导扇区时,CPU处于称为“16位实模式”的内存寻址模式。为了访问硬件外设,有几种方法,包括内存区域和IN和OUT汇编指令。视频可以通过内存地址范围0xA0000-0xBFFFF访问。在这个内存位置写入字符将在屏幕上绘制字符。写入某些高于0xC0000的区域会操作视频BIOS寄存器,例如更改视频模式。
C最初被创建用于将UNIX移植到PDP-11,该系统使用类似于今天的x86的内存映射I/O方案。如果没有指针,UNIX永远无法在PDP-11上运行。
像F#,C#,Ruby,Python,Lua等语言不能在不修改核心语言的情况下实现此功能。C和C ++可以:
/* Assuming 16-bit DOS environment, 80x25 character video mode. */
char* video = 0xA0000;
video[1] = 'H';
video[3] = 'e';
video[5] = 'l';
video[7] = 'l';
video[9] = 'o'; /* prints "Hello" in the top-left corner of the screen.

并非所有系统都具有内存映射IO。一些CPU具有“端口”。 - Nosredna
@Nosredna:这导致了更少适合初学者的技术,比如Duffs设备。 - SingleNegationElimination
@Nosredna:我提到了x86的IN/OUT指令。我意识到并非所有系统都使用MMIO,但这是相当普遍的,最初为C语言设计的PDP-11就使用了MMIO。 - greyfade

10

你把指针算术和不可变指针(也称为引用)混淆了。 所有这些语言,包括你没有提到的Java,都有引用。 引用比指针稍微弱一些,但在需要使用指针算术或双重或三重指针的阶段之前,你不会注意到这一点。 但实际上,在底层,引用与指针是相同的东西,只是语言不允许你对它们做任何想做的事情(即它们不是一级对象)。

考虑这个Python代码:

class X: z=13

y=X()
def f(aa): aa.z = aa.z+1

print(y.z)
f(y)
print(y.z)

f()会改变y.z的值,这正是使用指针编写相应的C或C++代码所会发生的。


2
最终,我会发布的答案是:“你正在使用指针,但你不知道它”。 - Tom Leys

4
简而言之,因为C++针对系统编程。
这意味着C++的方向是从上到下实现几乎所有东西。
其中包括操作系统,需要对机器地址发生的情况有一定的控制,而不仅仅是VM映射的逻辑地址。
这也包括用于C++或任何其他语言的编译器,需要实际实现这些语言使用的抽象。
这还包括性能受限的设置,例如嵌入式设备编程或高性能计算,在这些情况下,必须以一种非常谨慎地使用内存、指令、代码大小和任何其他受限资源的方式进行编程。
没有多少语言针对这个广泛的任务范围。按照这个标准称其他语言强大是相当误导人的,因为这些语言根本不适合这些任务。

我记得当Java出现时,很多讨论都是:“嗯,没有指针——这将有限的用途。” - Nosredna

4

C++为什么需要并使用指针?

C++本身并不需要指针,是程序员需要它们。比如一些编写设备驱动的程序员确实需要使用指针。

因此,必须有一些语言允许直接访问原始内存。C++恰好是其中之一。


如果没有指针,我们还需要C++吗?我们可以在最底层使用C和汇编语言,在顶层使用Java或C#。 - Nosredna
C++是一种多范式语言。我不知道如果没有指针它是否会有同样的成功,但也许吧。 - Nick Dandoulakis

1
指针提供了一种按引用传递的方式,这在一些需要传递大型数据结构的程序中非常关键。你只需传递一个小指针,而不是传递100mb。没有“指针”的语言通常有一种按引用传递的机制。

3
C++ 中也有“引用(reference)”的概念--void f(int& bah)通过引用方式传递参数(在底层是一种指针)。指针拥有更多的功能(因此程序员必须承担更多责任!),特别是“地址算术运算”! - Alex Martelli
就此而言,试着在C#或Java中编写一个不显式声明参数为引用的交换函数。这变得有点困难了。它们使用了类似于按引用传递的东西,但更好的名称此时我无法想起来。 - Jimmy
我理解在内部,C#、Java和其他语言都使用指针,但我的问题是为什么C++让你“在前台”处理指针。现在我明白了。 - RCIX

1

大多数高级语言本身并没有指针,但它们使用类似的结构。这里有一个例子。在C++中,如果你有像这样的东西:

Foo myObject();

你已经声明了一个 Foo 的实例,它总是会是 Foo 类型。你不能声明一个 Foo 并实例化另一种类型而不使用指针。然而,在 C# 中,你可以轻松地做到这一点:

Foo myObject = new Bar(); // assuming Bar derives from class Foo

在C++中唯一的方法是使用指针(多态性的感谢)。C#使用某种形式的指针,但将使指针使用变得如此“困难”的混乱内容抽象出来。

2
C#,就像Java一样,在引用方面做得很好(比C++更好),但也提供指针(与Java不同!)因为有些工作(例如需要地址算术的工作)只能通过这种方式更好地完成! - Alex Martelli
由于指针仅是特定大小的整数,您也可以在Java中使用“指针”并进行指针算术运算! .NET中通常用于指针(IntPtr)的特定类型并不妨碍您也使用“int指针”。 因此,如果您从这个角度来看:所有语言都可以拥有指针。问题只在于是否可以直接获取内存块(对象等)的地址。(我认为您还可以通过从Java调用本机代码来完成此操作) - mmmmmmmm
@Jimmy - 多态也可以通过C++引用实现。 - Daniel Earwicker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接