空指针和未初始化指针的区别是什么?

7
为什么可以打印空指针的值,但不能打印未初始化指针的值?我的意思是,当将指针初始化为nullptr时,你只是明确地让指针指向了一个不存在的位置,对吧?如果是这样,那不初始化它岂不是一样吗?还是我错过了什么?感谢!非常感谢!

1
想象一下你的小女儿在繁忙的道路旁边走过。你认为告诉她不要动和什么都不告诉她是一样的吗? - Kerrek SB
1
你自相矛盾:“将指针初始化为nullptr,你明确地让它指向了‘无处’”。因此,你是有意地使用已知的值进行初始化,但仍然以某种方式使其指向无处……未初始化的指针甚至不能指向无处,它总是具有一些随机(“垃圾”)值,可以将其视为某个内存地址。 - ForceBru
1
@ForceBru:不,原始陈述是准确的。一个具有nullptr值的指针确实“指向无处”,并且没有任何“随机”或“垃圾”值。那些具有“随机”或“垃圾”值的指针实际上是不确定的,并且不能被视为任何内存地址。 - Lightness Races in Orbit
@BoundaryImposition,糟糕,我实际上在最后一句话中谈论的是未初始化的指针,我会尽快编辑。 - ForceBru
1
@ForceBru:我仍然坚持我所说的话。 - Lightness Races in Orbit
显示剩余2条评论
5个回答

12
指向无处和未初始化是两个不同的概念。 严格来说,未初始化的指针具有不确定的值。它不是指向特定位置“无处”或对象的指针。它只是...“耸耸肩”。您还不能对其执行任何操作。
“特定位置'无处'?”你问道。“这是什么胡说八道?”好吧,确实如此。它并不真正指向“无处”。空指针有一个特定的值和特定的表示形式。它不指向对象,但它仍然是一个单一、可预测、已知的值,专门为此保留。
有效指针:我在Kerrek的房子里、在工作、在酒馆等地方。
失效指针:我在Kerrek的房子里,但是来自莫斯科的Vlad炸了它 :( 我现在正在看火焰,有点哭泣。
空指针:我在家里睡觉。请在早上回来。
未初始化的指针:我喝醉了,不知道我在哪里,甚至不知道我还活着没有。

2
我需要观察 Vlad。 - Kerrek SB
谢谢!但是我可以用什么词来代替“nowhere”呢? - user7926026
@Hei: “nowhere” 就可以了;这是我们许多人使用的口语术语。我只是想解释一下,技术上的实际情况并不真正符合英语语言的暗示。这似乎是你困惑的核心。当然,说一个空指针不指向任何地方是正确的,但未初始化的指针也是如此,因此我们需要更多地了解它们。 - Lightness Races in Orbit
@BoundaryImposition 任何变量都不可能指向无处或不包含任何内容。操作系统为每个变量分配一个RAM中的位置,由于它是RAM,这意味着位置“0x1111111”或任何其他位置都具有并保留旧值或垃圾值。 RAM中的每个位都是0或1,两者都表示一个值。因此,未初始化的变量或指针将包含垃圾或随机值。如果您进一步裁决这种推理,知道指针实际上只是RAM中索引的数字,那么您可能会说未初始化的指针指向某个地方,嗯? - Keith Becker
@KeithBecker 您的整个评论抽象级别设置错误。 “知道指针实际上只是RAM中的索引号码” 不是这样的。“您可能会说未初始化的指针指向某个地方,嗯?”不是这样的。它的值是不确定的,这种状态与根本没有值的状态无法区分。“RAM中的每个位都是0或1,两者都代表一个值。” RAM与此完全无关。我们不是在CPU上切换位; 我们正在使用高级计算机编程语言进行编程。 - Lightness Races in Orbit
显示剩余3条评论

3

指针(类型为T)是一种值,类似于其他值,例如整数或字符串,它可以处于以下三种状态之一:

  1. 它可以指向对象或一个对象的后面(两者不排斥),或者指向一个函数。如果指向对象或函数,则可以对该指针进行间接引用。

  2. 它可以具有特殊值“null”,在这种情况下,它与T()nullptr以及其他表达式(如0NULLT(0)T(nullptr))相等。

  3. 它可能是以上任何一种都不是。这适用于未初始化的T类型变量的值,但永远不适用于T的prvalue。如果指针曾经指向一个对象但该对象的生命周期已结束,也会发生这种情况。

请注意,只有第二种情况(空指针)是可以通过编程方式检查的!你通常无法确定非空指针是否有效(除了将指针与一组已知的有效指针进行比较的情况外)。


谢谢,兄弟!现在感觉清晰多了。为什么不能选择多个答案呢?毕竟你们几乎都给我提供了很棒的回答,因此选择起来有些困难。 - user7926026
1
@Hei:不用担心,只要选择你认为有帮助的就可以了。 - Kerrek SB
@Hei:一般的经验法则是永远接受“我的”答案,因为我的军队最大,我知道所有铀的存放地点。(最初这只是为了防止弗拉德试图烧毁我的房子,但事情有点…失控了) - Lightness Races in Orbit
@Hei:BoundaryImplosion还需要声望才能负担得起他/她的下一个屏幕名更改... - Kerrek SB
是的,这也是真的。身份盗窃并不像电视上看起来那么便宜。 - Lightness Races in Orbit
那听起来很合理。 - user7926026

2
我是说,当将指针初始化为nullptr时,你只是明确地使指针指向无处,对吗?如果是这样,那不就和不初始化它一样吗。
不,两者不同!
参考:C++ Primer 指针存储的值(即地址)可以处于以下四种状态之一:
1. 它可以指向一个对象。 2. 它可以指向一个对象结束后紧接着的位置。 3. 它可以是空指针,表示它没有绑定到任何对象。 4. 它可以是无效的;除了前面三个状态之外的任何值都是无效的。
当我们说指针被初始化为nullptr时,这意味着该指针未绑定到任何对象。
未初始化的指针处于无效状态(即点4)。
您可以检查指针是否为空,但是解引用未初始化的指针是未定义的,并可能导致运行时崩溃。

1
一个未初始化的指针不会“指向垃圾值”,它本身就是垃圾值。而一个空指针也不会“指向nullptr”。 - Kerrek SB
这个想象中的性能成本是很有趣的,但与什么相比呢?与根本没有指针相比?显然是这样! - Lightness Races in Orbit
1
不,先生,不是这样的。 - Lightness Races in Orbit
@BoundaryImposition:为什么不是呢?你的“indeterminate”值和垃圾值有什么区别? - ani627
@KerrekSB:表述清晰。你是对的,我们不应该解引用空指针,而应该检查它是否为“nullptr”。 - ani627
显示剩余7条评论

2

nullptr 意味着无处可指,这是可以接受的!将指针初始化为此定义值是一个很好的习惯。 但如果未初始化,则它可能指向任何地方,这是未定义的,并且可能导致未定义的行为。


好的,非常感谢!但是当你说“但是未初始化时它可以指向任何地方”时,你实际上是在说它实际上指向了某个地方 - 那么为什么我不能打印出这个值呢?不过,它至少应该是0吧? - user7926026
@嘿,你可以打印指针的值(即地址),但是你不能对其进行解引用,以打印所指向的值,因为这可能会导致未定义行为,例如这可能是一个无效或受限制的地址。不仅仅是0,它可以是任何可以在该指针中表示的数字。 - Rama
@BoundaryImposition,嗨,你可以违反规则,只是为了好玩,但请不要在生产环境中这样做! - Rama
确实。理想情况下,完全不需要,但我无法控制 :) - Lightness Races in Orbit
@BoundaryImposition,因此如果标准规定您不能访问该值(如果这是如何表达的),为什么允许将指针初始化为空? - user7926026
显示剩余6条评论

2
在一些语言如C#和Java中,未初始化的指针包含NULL。
另一方面,C++遵循不浪费任何时钟周期做你没有明确要求的事情的哲学(语言在这方面的成功程度是一个不同的故事),所以C++不会浪费时间将指针初始化为NULL,因此在C++中,未初始化的指针被认为是包含垃圾值。
垃圾值的问题在于,后来你不能说if( pointer == garbage ) { pointer = someMeaningfulValue; },因为你不知道垃圾值是什么,无法进行比较。你无法重现它。
因此,通过说pointer = NULL;,你已经用一个预先知道的值(代表“指向空”)初始化了指针,所以你可以稍后安全地执行if( pointer == NULL ) { pointer = someMeaningfulValue; }

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