代码中的未初始化指针

41

我正在学习C++,我了解到如果指针未初始化,则可能会指向内存中的随机位置,并创建一些问题,这些内存可能被其他程序使用。

现在如果是这种情况,我们就不应该在代码的任何部分中出现以下行:

int* ptr;

相反,我们应该有类似于

int* ptr = NULL; //Is this going to avoid the problem

请给出建议,因为我在很多书中都看到了第一行(int* ptr;),所以我有这个疑问。如果可能的话,请举些例子。


在使用指针之前请检查是否为空,或者使用引用来避免此问题。 - DumbCoder
1
几乎所有的编译器都有一个标志,可以警告你关于这个问题。打开它。 - Martin York
2
如果一个指针没有明确设置为NULL,检查是否为NULL将不起作用。 - user1043000
8个回答

50
int* ptr = NULL; //Is this going to avoid the problem
这将导致ptr指向NULL,你可以明确地检查它作为默认/未初始化值。它可以防止您所描述的问题,但是一个不小心的程序员仍然可能在没有检查的情况下意外解除对空指针的引用,从而导致未定义的行为。主要优点是方便您检查ptr是否已经被初始化成任何东西,即:
 if (ptr != NULL)
 {
     // assume it points to something
 }

由于这种用法相当常见,不将指针初始化为NULL会非常危险。指针将被初始化为非NULL的垃圾值,实际上并没有指向任何真正的内容。最糟糕的是,上面的检查将通过,如果恰好该指针中的地址是您可以合法访问的内存,则会导致更严重的问题。在某些嵌入式环境中,您可能能够访问内存的任何部分,因此您可能会意外地损坏随机部分的内存或执行代码的随机部分。


2
如果你这样做,同样重要的是要记得在指针被释放时再次将其设置为NULL,以保持一致性。否则,你不能安全地假设非NULL指针是可引用的。 - Rune Aamodt
那么 @Doug 你的意思是 int* ptr; 永远不应该被使用吗?但是 @Sasquiha 写道,只要我们不对其进行解引用,它就是安全的。 - munish
@munish,如果您从未取消引用它,那么它是安全的,但如果您从未取消引用指针,那么指针的意义何在? - Doug T.
嗯,我明白你的意思,但我在想。如果你考虑一个例子,在我的代码中有一行 int* ptr;,然后我在100或1000行之后对它进行解引用,那么在此期间,也就是在它到达第1000行之前,它应该指向一个随机位置。它将在很久以后被解引用。 - munish
这个垃圾值从哪里来的呢?编译器随机给出这个值吗? - heretoinfinity

12

始终初始化你的变量。

偶尔,你可能想要将其初始化为NULL,但大多数情况下,你应该能够将指针初始化为它应该持有的值。尽可能晚地声明变量,并在那个点进行初始化,而不是在代码中后面15行进行初始化。


人们想使用指针的主要原因之一是因为他们想要一个句柄来引用某个东西,并能够查看该东西是否存在(通过检查 NULL)。如果您可以在声明变量时进行初始化,为什么不只是在堆栈上分配该对象并完成它呢? - Doug T.
@Doug:通常是因为你需要它超出当前作用域的生命周期。我真的不明白检查句柄是否为空会改变什么。在这种情况下,你应该尽可能晚地声明它,并尝试立即初始化它。 - jalf

6

这行代码:

int* ptr;

并不保证将指针的值初始化为特定值。

以下是代码:

int* ptr = NULL;

将指针初始化为指向地址零,实际上从来不会有任何有用的内容存在,而且通常会检查它是否为无效指针值。

当然,正如Doug T.所说,仍然有可能尝试在未经检查的情况下使用该指针,因此它会崩溃。

明确地初始化为NULL的优点是确保在将其设置为有用的内容之前对指针进行解引用将导致崩溃,这实际上是一件好事,因为它可以防止代码在掩盖严重缺陷的同时“意外”运行。


3

如果由于某种原因无法在声明时初始化指针,最好将其初始化为NULL。例如:

Object *ptr = new Object();

通常,函数可以检查指针的值是否为NULL,以验证指针在初始化之前已被初始化。如果您没有将其明确设置为NULL,并且它指向随机值,则可能会导致引用无效而导致段错误。


1
最好始终初始化一个指针。但不总是将其初始化为NULL更好。如果您知道它应该具有的值,直接将其初始化为该值。 - jalf

2

C++继承了C的特性,它并非被设计成安全的语言,而是为了追求效率。因此,自动变量不会被初始化。你需要确保在使用指针之前将其初始化(虽然许多编译器如果你没有初始化变量会发出警告)。


1

如果指针没有被使用,编译器将会忽略它。在我的看法中,将其初始化为NULL是安全的做法。

你确定你没有混淆函数声明吗?一个函数被声明为

char* do_something(const char* one,const char* two);

在这种情况下,指针用于指定要传递的参数类型。


1
int a,*ptr;

现在
print(ptr,*ptr)

在上述代码中,可能有两种情况:
  1. It'll execute if default value in ptr is not the address of some used memory of program.

    Output:

           ptr             *ptr
    eg.  0x400730       -1992206795
    
  2. It'll give error (segmental fault) if default address in the ptr is the address of some used memory of program. E.g. if the address of variable a in the memory is also 0x400730.


-2

在C++中,你应该尽量避免使用普通指针。标准库类、智能指针(直到C++0x只存在于各种库中,如Boost或Loki)和引用可以并且应该在大多数情况下代替它们。

如果你无法避免使用指针,最好声明它们时进行初始化,在大多数情况下不应该是NULL,而是实际的目标值,因为在C++中,你可以自由地混合声明和表达式,所以你只能在有意义的值的点上声明变量。

这在C语言中并非如此,你必须经常使用指针,并且所有变量都必须(或者在C99之前必须)在作用域的开头声明。因此,许多人仍然有从C语言继承下来的不适用于C++的坏习惯。


7
这是错误的。在写得好的C++代码中,普通指针仍然是最常见的类型。而且,虽然您正确地指出了应该尽可能用最终值初始化指针,但使用指针的一个可能原因恰恰是您可能无法这样做,并且必须稍后设置它。(否则,您需要一个引用。) - James Kanze

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