2、指针与变量:指针的声明与初始化、指针与普通变量的关系、空指针与野指针

好,咱们今天聊聊指针和变量那点事儿。

说实话,指针这东西,刚学的时候我也觉得绕。但后来我发现,只要搞明白它和普通变量的关系,后面就顺了。说白了,指针就是一个“存放地址的变量”。

2.1 指针的声明与初始化

先看声明。指针的声明长这样:

int *p;      // p 是一个指向 int 的指针
char *cp;    // cp 是一个指向 char 的指针
double *dp;  // dp 是一个指向 double 的指针

注意那个星号 *,它告诉编译器:这个变量存的是地址,不是普通数值。

我个人习惯把星号紧挨着变量名写,比如 int *p。这样读起来更自然——「p 是一个指针,指向 int」。当然也有人写成 int* p,语法上没问题,但容易让人误解成 int* 是一种类型。其实 int* p, q 这种写法里,只有 p 是指针,q 是普通 int。你想想看,是不是挺坑的?

初始化就更关键了。指针必须指向一个合法的地址才能用:

int a = 10;
int *p = &a;   // 把 a 的地址赋给 p

这里的 & 是取地址运算符。它就像一把钥匙,帮你找到变量在内存里的门牌号。

核心要点:指针存的是地址,不是值。想拿到指针指向的值,用 *p 解引用。

2.2 指针与普通变量的关系

普通变量和指针,其实是一枚硬币的两面。

普通变量直接存值,比如 int a = 10;,a 这个盒子里装的就是 10。指针变量存的是地址,比如 int *p = &a;,p 这个盒子里装的是 a 的门牌号。

它们之间的关系可以用这张图来理解:

变量 a 10 地址: 0x1000 指针 p 0x1000 地址: 0x2000 指向 *p == 10 p == &a &p == 0x2000

你看,p 里存的是 a 的地址。通过 *p 就能拿到 a 的值 10。这就是指针和普通变量最本质的关系——指针是间接层,变量是直接层。

我在项目中遇到过这样一个场景:需要在一个函数里修改多个变量的值。如果传普通变量,函数里改的是副本,外面纹丝不动。传指针就对了,函数里 *p = 新值,外面也跟着变。这就是指针的威力。

小技巧:用 printf("%p", p) 打印指针的值,看看地址长什么样。我当年就是这么把指针搞明白的。

2.3 空指针与野指针

这两个概念,是新手最容易踩的坑。我一个个说。

空指针

空指针就是指向「空」的指针。在 C 里用 NULL 表示,C++11 之后推荐用 nullptr。

int *p = NULL;   // C 风格
int *q = nullptr; // C++ 风格

空指针的意义很明确:这个指针当前不指向任何有效对象。它是一种安全状态,你可以判断它是不是空,然后决定要不要用。

我曾经在代码里看到有人这样写:

int *p;
// ... 中间隔了 200 行代码 ...
if (p != NULL) {
    *p = 10;
}

嗯,这里有个大问题——p 根本没初始化!它不是空指针,它是野指针。后面会讲。

警告:对空指针解引用会导致程序崩溃。所以用之前一定要检查:if (p != nullptr) { ... }

野指针

野指针才是最可怕的。它指向一个随机的、非法的内存地址。你根本不知道它指向哪。

野指针是怎么产生的?常见三种情况:

  1. 未初始化:int *p; 然后直接用。p 里是个随机值。
  2. 指向已释放的内存:free(p) 之后没把 p 置 NULL,继续用。
  3. 指向栈上变量的地址:函数返回后,局部变量的地址就失效了。

看个例子:

int* getBadPointer() {
    int a = 10;
    return &a;  // 危险!a 是局部变量,函数结束就销毁了
}

int main() {
    int *p = getBadPointer();
    *p = 20;  // 野指针!访问了已释放的内存
    return 0;
}

我曾经在维护一个老项目时,遇到一个间歇性崩溃的 bug。查了三天,最后发现是有人把局部变量的地址返回了。那个地址在函数返回后被系统回收,但调用方还在用。崩溃时间完全随机,特别难复现。

从那以后,我给自己定了个规矩:指针要么指向合法对象,要么就是 nullptr。没有中间状态。

避坑指南:

  • 声明指针时立即初始化,不知道指向哪就赋 nullptr
  • 释放内存后,立即把指针置 nullptr
  • 不要返回局部变量的地址
  • 解引用前,先判断是不是 nullptr

2.4 总结一下

指针和普通变量的关系,说白了就是「间接」和「直接」的区别。指针存地址,变量存值。通过 & 取地址,通过 * 解引用。

空指针是安全的「空」状态,野指针是危险的「随机」状态。写代码时,脑子里要时刻清楚:这个指针指向哪?它合法吗?

嗯,这一节就到这。记住我说的,指针这东西,多练练就熟了。

个人建议:刚开始学的时候,每写一个指针,就在纸上画一下内存图。变量在哪,指针指向哪,画清楚了,代码就不会错。

可可精品资料库