为啥 C++ 使用指针? [关闭]

Posted

技术标签:

【中文标题】为啥 C++ 使用指针? [关闭]【英文标题】:Why does C++ use pointers? [closed]为什么 C++ 使用指针? [关闭] 【发布时间】:2009-07-04 04:48:50 【问题描述】:

为什么 C++ 需要和使用指针?我知道它们增加了语言的力量,但它们使初学者更难理解。 F#、Java、Ruby、Python、Lua 等语言没有它们也能正常工作,而且它们非常强大。

【问题讨论】:

en.wikipedia.org/wiki/History_of_programming_languages cm.bell-labs.com/cm/cs/who/dmr/chist.html 一般来说是了解编程语言的一个开始。您正在将 C++ 与 C# 和其他更新的编程语言进行比较。这个上下文有助于理解为什么 C++ 使用指针 因为如果你正确地执行 strcpy,它是复制字符串的最快方法。如果运行时性能很重要,C/C++ 代码几乎等同于汇编代码,但编写起来却少了很多痛苦。这似乎与今天的处理器无关,但在 80 年代使用 8 MHz 处理器时,它肯定是 ;-) @RCIX,所以你还是不明白为什么在某些情况下你会选择更强大的语言?假设我正在为现有的音乐程序编写混响插件。调用程序告诉我音频缓冲区在内存中的位置。如果我在 Java 中,我可以读取缓冲区广告中的字节并替换它们吗?我的Java程序甚至可以编译成音乐程序想要的dll吗?也许这是可能的,但这并不简单。我知道如何在汇编和 C 中做到这一点。我不知道如何在 Java 中。 (注意:您可以使用包装器来实现。但我敢打赌,包装器是用 C++ 编写的。) 【参考方案1】:

您提到的所有其他语言(至少您忘记了 Java !!!),虽然每种语言都非常有用且可用,但不要让您像 C++(和 C)允许的那样接近机器:简单地说换句话说,所有这些语言都强加给你更高层次的抽象......这可能大部分没问题,但偶尔会妨碍你。

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

建议初学者远离这种强大的功能和(不可避免的)复杂性——但不是每个程序员都是初学者,也不是每一点代码都需要(或者,实际上,完全可以忍受!-) 处于一个以“让我们保护可怜的 shmucks 免受自身伤害”为主要设计目标的环境中!-)

【讨论】:

“建议初学者远离这种强大的力量和...无论如何,指针提供的相同功能。 恕我直言,既然 Pascal 已经过时了,初学者可以从 Python 或 Ruby(如果你在教育领域的“让他们早日轻松成功”阵营)、D 或 C# 开始最有用或 Java(更严格一点),或 Haskell 或 SML(如果他们是数学专业的;-)[或者可能是其他一些函数式语言]。我对 Scheme 有一段由来已久的爱情故事,但我明白为什么 MIT 放弃了它,转而支持 Python…… 通常当我看到亚历克斯回答问题时,我会阅读它以了解比我能提供的更好的答案。虽然我不是 C++ 专家,但 Alex 的 cmets 在他们所说的方面很有根据,但在我看来,他们并没有提供问题的正确答案。答案很简单,正如 bluebrother 已经说过的:从一开始,Stroustrup 就将 C++ 作为 C 的超集作为高优先级,因此既然 C 有指针,C++ 就必须有它们。去年秋天,Stroustrup 做了这个演讲:dcacm.org/archives/Lists/2008%20Events/Attachments/6/… 我认为有很多不同的学习方法。我一直记得指针是一个非常直接,因此非常容易理解的概念,比任何类、对象、引用和实例都更不透明。虽然,是的,基本工具让你以非常基本的方式摸索,但它们也教你非常基本(和有用)的概念,有助于理解更复杂的事物。因此我宁愿说“从指针开始”,因为它使以后更容易理解概念(和引用的使用)。当然,前提是你有足够的时间学习。 我在大学时跟随 Pascal 学习了指针,然后在下一门课程中使用了 C 实验室。然后在工作中(我每次都感谢我的前任老板!)我学习了 C++。在大学的第二年,他们将学习语言从 Pascal 更改为 Java……我很高兴一年前出生:)【参考方案2】:

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

指针已经存在了很长时间。他们在 Pascal 和 C 中。当 C++ 出来时,它会在没有指针的情况下丢失。

【讨论】:

+1,还有一个响亮的阿门! -- 为什么一切都适合初学者?! 指针有什么难理解的?即使在今天,程序员也知道指令和数据存储在内存中的可寻址位置,对吧?指针只是说明位置是什么。什么这么难?不过,我在 C 之前学习了汇编语言。也许汇编语言程序员在学习 C 指针时有优势。 @RCIX。我们不应该有航天飞机。对于初学者来说,它们很难飞。 老实说,C++ 并不难。如果您编写的代码“几乎做任何事情都会在您最意想不到的时候崩溃”,这更多地反映了您的编码能力比语言差。一个可怜的工匠责怪他的工具。 对不起,但我真的不相信任何经过一些学习后无法理解指针的程序员的能力。这个概念真的没那么难。【参考方案3】:

我还没有在这里阅读的一个原因:

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

【讨论】:

没错,C++ 需要做 C 能做的所有事情,才能成为程序员愿意使用的语言系统。【参考方案4】:

C# 有指针,没有它们我无法过得很好。这完全取决于你在做什么,学习指针对你作为开发人员来说非常有用。问题不在于为什么,而在于何时使用它们。

【讨论】:

【参考方案5】:

这里有很多很好的答案,但没有太多很好的例子说明为什么需要。 ... 或者为什么 C 有时被称为“可移植汇编语言”。

在机器的最底层抽象上,有大量的硬件功能是通过内存范围来访​​问的。这些内存地址通常使用各种类型的硬件非常标准化。

例如,当 x86 计算机首次启动并且 Bios 已加载并启动引导扇区时,CPU 处于称为“16 位实模式”的内存寻址模式。要访问硬件外围设备,有几种方法,包括内存区域和 IN 和 OUT 汇编指令。视频可在内存地址范围 0xA0000-0xBFFFF 访问。写入此内存位置会将字符绘制到屏幕上。写入 0xC0000 以上的某些区域会操纵视频 BIOS 寄存器,例如,可以更改视频模式。

C 最初是为了将 UNIX 移植到 PDP-11 而创建的,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:这会导致对初学者不太友好的技术,比如 Duffs 设备 @Nosredna:我在 IN/OUT x86 指令中提到了这一点。我意识到并非所有系统都使用 MMIO,但它相当普遍,而且最初设计 C 的 PDP-11 使用 MMIO。【参考方案6】:

您将指针算术与不可变指针、AKA、引用混为一谈。所有这些语言,包括你没有提到的 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++ 代码中会发生的情况。

【讨论】:

+1 最后,我会发布的答案 - “你正在使用指针,但你不知道它”【参考方案7】:

简而言之,因为 C++ 以系统编程为目标。

这意味着 C++ 的目标是实现几乎所有内容,从上到下。

这包括操作系统,您需要在一定程度上控制机器地址发生的事情,而不仅仅是虚拟机映射的逻辑地址。

这还包括 C++ 或任何其他语言的编译器,这需要实际实现这些语言使用的抽象。

这还包括性能受限的设置,例如嵌入式设备编程或高性能计算,在这些设置中,必须以非常谨慎地使用内存、指令、代码大小和任何其他受限资源的方式进行编程。

不是很多语言都针对这种广泛的任务。用这个标准称其他语言强大是相当误导的,因为这些语言根本不适合这些任务。

【讨论】:

我记得当 Java 出现时,很多讨论是,“好吧,没有指针——这将是有限的。”【参考方案8】:

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

C++ 不需要任何东西。程序员需要它们,而有些程序员真正需要它们。就像正在构建设备驱动程序的程序员一样。 因此,必须有一些允许原始内存访问的语言。 C++ 恰好是其中一种语言。

【讨论】:

如果它没有指针,我们还需要 C++ 吗?我们可以在最底层使用 C 和汇编,在顶层使用 Java 或 C#。 C++ 是一种多范式语言。我不知道如果没有指针它是否会取得同样的成功,但是......也许。【参考方案9】:

指针提供了一种通过引用传递的方法,这在某些传递大型数据结构的程序中至关重要。您只需传递一个小指针,而不是传递 100mb。没有“指针”的语言通常具有通过引用传递的机制。

【讨论】:

C++ 也有“引用”的概念—— void f(int& bah) 通过引用获取参数(“隐藏的指针”)。指针有更多的权力(因此程序员必须承担更多的责任!),尤其是“地址算术”! 就此而言,请尝试在 C# 或 Java 中编写交换函数,而无需将参数显式声明为引用。突然有点难。他们使用与传递引用非常相似的东西,但目前我还没有找到更好的名字。 我知道在幕后,c# 和 java 以及所有这些都使用指针,但我最初的问题是为什么 c++ 让你在“幕前”处理指针。我现在明白了。【参考方案10】:

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

Foo myObject();

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

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

在 C++ 中执行此操作的唯一方法是使用指针(并且感谢多态性)。 C# 正在使用某种指针,但抽象出使指针如此“难以”使用的杂乱内容。

【讨论】:

C# 与 Java 一样,在引用方面做得很好(比 C++ 更好),但也提供指针(与 Java 不同!)因为某些工作(例如,需要地址算术)以这种方式更好地完成! 由于指针只是特定大小的整数,您也可以使用“指针”并在 Java 中进行指针运算! .NET 中通常用于指针(IntPtr)的特定类型并不妨碍您也使用“int 指针”。所以如果你从这方面看:如果你愿意,所有语言都可以有指针。问题是是否可以直接获取内存块(对象等)的地址。 (我认为您也可以借助从 Java 调用的本机代码在 Java 中执行此操作) @Jimmy - 多态性也可以通过 C++ 引用工作。【参考方案11】:

您可以在不使用指针的情况下在 C++ 中做很多事情。坚持参考和更高层次的东西,比如 STL。阅读 Accelerated C++ 适合初学者(尽管是使用另一种语言编程的人)的书。 C++ 可以以比 C 更高的方式进行编程。远离多重继承、编写自己的模板和一开始就使用指针之类的东西,你会没事的。如果您刚刚开始,请从一开始就学习虚函数和面向对象编程。远离超载。掌握前 50% 的语言,然后再难学的 50% 似乎就不那么令人不安了。

【讨论】:

【参考方案12】:

这个问题可以引发一场严重的火焰战争。 我一遍又一遍地问自己同样的事情,同时试图理解指针和 c++ 中的所有相关内容

因为 ruby​​、python 等语言处于另一个编码级别。它们离机器语言越远越抽象。但也许更慢。

另一个原因是 c++ 是一门非常古老的语言。许多概念来自人们不了解的时代,我认为这是一个严重的问题。 C++ 有它的优点,它可以让你编写非常快的代码并采取很好的捷径。但要权衡的是一种难以理解的语言和看起来像艺术但让后来使用它的人感到困惑的程序。

【讨论】:

我不同意你的断言“人们没有更好的了解”——如果需要指针,指针非常强大和有用。 “使用正确的工具完成工作”。许多初学者不通过任何结构化方法(即讲师指导的课程)学习,因此他们蹒跚而行,养成了不良习惯(SQL 注入漏洞、误用的“goto”语句、在视图中混合业务逻辑等)而不是“得到”诸如指针之类的东西——这真的很可惜。 是的,我真的非常不同意最后的说法。您今天使用的每个操作系统都是用 C/C++ 编写的。没有一个是用 Java、Ruby 或任何时髦的新语言编写的(甚至可以编写)。说编写操作系统的人“一无所知”是一种非常无知的说法。 @Bob Somers:既然您对当前操作系统的看法是正确的,我不敢打赌将来可能会有用 Java 或类似语言编写的操作系统。只要有硬件(CPU)直接实现这些语言的虚拟机,就会出现这种情况! @rstevens:你不能真正在硬件中实现虚拟机。你可以做到这一点的唯一方法是在固件中实现大量的虚拟机......无论如何这只是C代码......这就是我们已经拥有的。 :P 一旦有了物理机,VM中的VM就不能代表Virtual了。【参考方案13】:

垃圾收集 (GC) 被认为对于某些将使用 C++ 的环境来说开销太大,例如嵌入式系统,操作系统。使用高级引用,如果对象仍然可以访问,则无法删除它。假设 GC 存在,就可以保证安全性。如果不采用 GC 作为基本假设,C++ 将始终需要原始指针。

不出所料,该站点上最流行的 C++ 问题之一是“我如何以一般方式解决悬空指针问题?”,最流行的答案是使用引用计数智能指针,即就像一个穷人的GC。另一个答案是使用正确的工具来完成这项工作 - 如果您进行低级或嵌入式系统编程,C++ 可能是错误的工具。 C++ 在高级应用程序编程中的使用比它应该的要广泛得多。很多人浪费时间调试内存泄漏、内存损坏等,只是因为他们使用了错误的工具来完成这项工作。

使用指针的另一个原因是它们允许设备驱动程序的作者寻址特定的内存区域,这在与设备通信时通常很有用,因为某些内存区域被“映射”到硬件设备。但同样,这在很大程度上是一个低级系统编程问题。

【讨论】:

以上是关于为啥 C++ 使用指针? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

为啥 C++ 共享指针的行为不像迭代器的标准指针?

学习 C++ 指针使用以下代码运行到核心转储中,我真的不知道为啥?

为啥 C++ 允许通过指针访问枚举?

为啥在 C++ 中一个类的指针可以转换为另一个类的指针?

为啥允许将字符串文字分配给 C++ 中 char * 类型的指针 [重复]

使用指针 C++ [关闭] 指示 Vector 的索引