什么是空指针和空类型指针?

47

我正在浏览一些面试题,其中有一个关于空指针和空类型指针的问题 (点击这里查看),它声称:

没有返回类型的指针称为空指针。它可以是任何类型的数据。

这让我感到非常困惑!根据这个问题,似乎可以随意使用 void 和 null ,但我不认为这是正确的。 我认为 void 是一种返回类型,null 是一种值。但我只是一个新手程序员,不能确认自己的理解是否正确。

请您解释一下空指针和空类型指针分别指什么。我不是在寻找区别 between null and void。


5
这是一个对一个不好的问题的糟糕回答,与 CSS 无关。忽略它并继续前进。 - CB Bailey
3
哈哈,实际上CSS是一家公司 :P - Shouvik
1
这是一家公司,提供了我见过的最糟糕的回答来应对一个愚蠢的面试官问题。 - Nicol Bolas
9个回答

55

这两个概念是正交的:

  1. void指针(void *)是指向某个内存位置的原始指针。
  2. 空指针是一个特殊的指针,根据定义不指向任何东西。它可以是任何类型的指针,包括void指针。

一个void指针可以是null或非null:

void *void_ptr1 = nullptr;
void *void_ptr2 = malloc(42);
void *void_ptr3 = new Foo;               // void * can point to almost anything
void *void_ptr4 = (char*)void_ptr3 + 1;  // even somewhere inside an object
一个非 void 指针也可以是 null 或非 null。
Foo *f = nullptr;
Foo *g = new Foo;

请问您能否举个例子?您是指像指向void函数之类的指针吗?我是新手,如果您能详细解释一下,我会更容易理解 :) - Shouvik
14
类型void *的意思是“指向内存的指针;我不知道那里存储了什么数据”。任何“普通”的指针(例如 int *char *MyStruct *)都可以隐式转换为 void * 类型;它代表着原始的“一小块内存”。 - Chowlett
@Chowlett:是的,我在描述时有点不小心。已经修改过了。 - Marcelo Cantos

32

请忘记那个答案吧。来自您链接中的一句话:

"没有返回类型的指针称为空指针。"

这是非常错误的。一个指针的返回类型?真的吗?这是一个糟糕的来源...

void* 是通用指针类型,因为任何指针类型(除了指向const和/或volatile的指针)都可以隐式转换为void*。换句话说,您可以将任何指针分配给类型为void*的变量。空指针是指针0。


谢谢,我也猜到了。现在只是为了问题坚持下去... :) - Shouvik
1
实际上,一个空指针可能不是值为'0',尽管我从未见过其他值。在某些奇怪的平台上,0可能是一个有效的指针值。 - Gianni
1
@Gianni 是的,你说得对,我很高兴这个信息可以通过你的评论留在我的回答中。 - Armen Tsirunyan
这并没有解释OP所寻找的区别。 - Chubsdad
@Gianni:是的和不是。虽然空指针的底层表示(字节)取决于实现,但在C++语言中,0代表空指针。当需要将0视为指针并根据实现生成正确的底层表示时,编译器会生成适当的代码。 - Matthieu M.
显示剩余2条评论

29

void类型通常意味着没有给出任何类型信息。

您应该始终记住,指针传递两个信息:所指数据的类型(intdouble等),它指定了如何解释它,以及指向数据的地址,它指定了您可以获取指向数据实际值的位置。

类型信息在指针的类型中(double*int*等),而数据的地址是指针变量中包含的实际值。

因此,void指针(void *)是一个不指定任何类型信息的指针。它告诉您数据在哪里,但不告诉您如何解释它。您知道在那个地址有某些东西,但您不知道它是intdouble还是一组飞牛。要实际使用这样的数据,必须以其他方式获取其类型信息(例如使用其他魔术参数),将该指针强制转换为常规指针类型,然后像平常一样使用它。

void *通常用于C语言中提供对泛型编程的某种支持;例如,请参见C库函数qsort

相反,NULL指针是指向无处的指针。在这种情况下,通常存在指针的类型信息,但缺少所指数据的地址。当然,可能有一个是NULLvoid *

快速示例(假设将v声明为double v;):

                         Type information present
             +----------------------+----------------------+
             |          ✔           |          ✘           |
         +---+----------------------+----------------------+
    p  c |   |                      |                      |
 v  o  o | ✔ | double * ptr = &v;   | void * ptr = &v;     |
 a  i  n |   |                      |                      |
 l  n  t +---+----------------------+----------------------+
 i  t  e |   |                      |                      |
 d  e  n | ✘ | double * ptr = NULL; | void * ptr = NULL;   |
    d  t |   |                      |                      |
         +---+----------------------+----------------------+

小知识: 在当前标准中,NULL保证是0。

在语言的其他领域中,void总是用于指定类型缺失。将其用作返回值(注意:我现在谈论的是void,而不是void *)意味着该函数不返回任何值,并且将表达式转换为void是一种丢弃值的花哨方式(您向编译器和其他程序员表明您有意识地不使用某个值)。


12

请告诉我们:以下有何不同:

  • 气罐和无气情况之间的区别
  • 曲奇罐和没有饼干之间的区别
  • 术语“钱”和“空袋子”的区别

如果你理解了这些,就能够掌握 null vs void* 的困境。


1
我认为混淆是真实的,因为这个问题... SO应该是所有与编码相关的知识来源,因此我认为这是一个合适的问题。如果您有不同的感受,很抱歉... - Shouvik
@Shouvik:你是什么意思?这确实是对你问题的最佳答案!字面上 :) - Armen Tsirunyan
1
嗯,就像我之前提到的那样,我不是一名经验丰富的程序员,现在对于仅仅能够组合一段程序已经不再感兴趣了,我更想理解编程语言及其更精细的方面。虽然我看到这两者之间缺乏比较的笑话... :) - Shouvik
哈哈,我懂了... :D 如果你说“没有油箱”、“没有饼干罐”和“没有空口袋”,我可能会更快地理解它... :) - Shouvik

9

void 是一种非类型。

null 是一种非值。


是的,我已经在问题中表达了这种差异.. 寻找指针的差异。 - Shouvik
void是一种类型,0或NULL是一个值。 - Armen Tsirunyan
@armen:void 是一种表示缺乏类型的类型。null 也是如此。 - Nicolas Repiquet

2

void *ptr 是一个指针,可以用来指向任何类型的数据。它可以是 intfloat 或者 double 等等。它没有初始的指针类型,只有指针类型的十六进制值,我们可以将这个指针赋值给任何类型的数据。

而空指针则是具有 NULL 值地址的指针,指针被赋予 NULL 值地址以防止在创建时使用指针访问其他可能包含其地址的数据。我认为在目前未使用指针时将其赋值为 NULL 是一种良好的编程技巧。


2
链接的文章是错的。它的第一句话:“没有返回类型的指针被称为空指针”,让我觉得很警觉。这篇文章非常混乱。
你几乎是正确的。“指向void的指针”是一种类型(不是“返回类型”)。任何类型的值都可以由函数返回,因此可以成为(函数的)返回类型。
空指针是一个指针,无论其类型如何,都指向空对象,这不是任何可以创建的有效对象。可以说空指针指向“没有任何东西”。
指向void的指针也可以为空;
void *nothing = 0;

这是完全有效的代码,只是说明这个指针能够指向一个未命名的对象,但现在它没有指向任何对象。

谢谢你的确认。顺便问一下,空指针有什么特定的用途吗? - Shouvik
@Shouvik 一个函数可以接受void*参数。如果您熟悉Java或C#,它大致相当于接受Object - Pedro d'Aquino

2

以下是指针算术运算的一些差异:

这源于void是不完整类型的事实。

void *vp;
vp++;     // error, incomplete type
vp += 2;  // same error

void *p = 0;
p++;      // still same error

int *p = 0;
p++;      // well-formed program, but UB ($5.6/5)

所以基本上,一个空指针并不好,但它是有效的代码块,对吧? - Shouvik
1
@Shouvik:不,不是这样的。有时候它非常好用,例如当你只想将其作为不透明句柄传递而不披露它指向的实际类型,或者当你不希望被调用的实体进行任何指针算术运算时。所以这取决于具体情况。 - Chubsdad
啊,好的...像闭包之类的东西吗? - Shouvik
@Chubsdad:你好,为什么你最后一个例子中的int ptr是UB?你能解释一下吗? - user2793162

1

空指针指向0x000000(这是不正确的访问指针),而void指针是指向未指定类型(void *)的正确指针。然而,void指针可以是空指针,但是解除引用指针将生成错误。


“Incorrect” 是一个对指针而言相当模糊的形容词。NULL 是任何指针的有效值,但在指针值为 NULL 的情况下并没有对象。此外,根据你的逻辑,void* 指针不能为 NULL,因为它既是“正确”的又是“不正确”的。这是明显不正确的说法。 - MSalters

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