空指针(null pointer)

在上一课(《指针简介》)中,我们介绍了指针的基本概念:指针是保存另一个对象地址的对象,可通过解引用运算符 * 访问该地址上的值。例如:

#include <iostream>

int main() {
    int x{ 5 };
    std::cout << x << '\n';      // 打印变量 x 的值
    int* ptr{ &x };             // ptr 保存 x 的地址
    std::cout << *ptr << '\n';  // 通过 ptr 解引用打印 x 的值
    return 0;
}

输出:

5
5

上一课还提到,指针不一定要指向有效对象。本课将进一步探讨“指向空无一物”的指针及其含义。

空指针(null pointer)

除内存地址外,指针还能保存一个特殊值:空值(null),表示“无值”。当指针持有空值时,称为空指针(null pointer),此时它不指向任何对象。

最简单的创建方式是值初始化

int main() {
    int* ptr{};  // ptr 现在是空指针
    return 0;
}

最佳实践
若暂时不打算让指针指向有效对象,请将其值初始化为空指针。

由于指针可通过赋值改变指向,初始为空的指针稍后也可指向有效对象:

int main() {
    int* ptr{};          // 空指针
    int x{ 5 };
    ptr = &x;            // 现指向 x
    std::cout << *ptr;   // 输出 5
}

关键字 nullptr

与布尔字面值 true/false 类似,nullptr 是 C++11 引入的空指针字面值,用于显式地初始化、赋值或传递空指针:

int main() {
    int* ptr{ nullptr };   // 初始化为空
    int value{ 5 };
    int* ptr2{ &value };
    ptr2 = nullptr;        // 置空
    someFunction(nullptr); // 作为实参传递
}

最佳实践
请使用 nullptr 而非旧式的 0NULL

解引用空指针导致未定义行为

与悬垂指针一样,解引用空指针将导致未定义行为,通常表现为程序崩溃:

int main() {
    int* ptr{};       // 空指针
    std::cout << *ptr; // 未定义行为,极可能崩溃
}

检查空指针

可像对待布尔值一样判断指针是否为空:

int main() {
    int x{ 5 };
    int* ptr{ &x };

    if (ptr == nullptr)
        std::cout << "ptr 为空\n";
    else
        std::cout << "ptr 非空\n";

    int* nullPtr{};
    std::cout << (nullPtr ? "非空\n" : "空\n");
}

输出:

ptr 非空
空

警告
条件语句只能区分空/非空,无法判断非空指针是否悬垂。

nullptr 避免悬垂指针

当对象销毁时,指向它的指针成为悬垂指针;编译器不会自动将其置空。因此,程序员应确保:

  • 指针要么指向有效对象,要么显式设为 nullptr
  • 解引用前检查非空,以规避悬垂或空指针。

旧式空指针字面值:0 与 NULL

旧代码中可见:

float* ptr{ 0 };   // 合法,但不推荐
ptr = 0;

#include <cstddef>
double* ptr2{ NULL };  // 不推荐

现代 C++ 应使用 nullptr(原因见 12.11 课)。

优先使用引用

引用与指针都能间接访问对象,但引用更安全:

  • 不能绑定空值,避免空引用。
  • 创建后不可重定向,减少悬垂风险。

若无需指针的额外能力,应优先使用引用。

笑话

你听过空指针的笑话吗?
没关系,你不会“解引用”它的。

测验

问题 1
a) 能否判断指针是否为空?如何?
答:能,用 ptr == nullptr 或隐式布尔转换 if (ptr)

b) 能否判断非空指针是否有效?
答:不能,只能保证非空;需人为避免悬垂。

问题 2
判断行为:
a) 将对象地址赋给非常量指针 → 可预测
b) 赋 nullptr可预测
c) 解引用指向有效对象的指针 → 可预测
d) 解引用悬垂指针 → 未定义
e) 解引用空指针 → 未定义
f) 解引用非空指针 → 可能未定义(若悬垂)

问题 3
为何将不指向有效对象的指针设为 nullptr
答:统一用“空”表示无效,解引用前只需检查非空,简化错误检测。

关注公众号,回复"cpp-tutorial"

可领取价值199元的C++学习资料

公众号二维码

扫描上方二维码或搜索"cpp-tutorial"