2. 指针与变量:指针指向基本数据类型、指针的赋值与修改、空指针与野指针

指针这东西,说白了就是变量的「门牌号」。你想想看,变量本身住在内存里,有自己的一亩三分地。指针不存数据,它存的是「数据住在哪儿」这个地址信息。我当年刚学C语言时,总觉得指针神神秘秘的,后来发现——嗯,它就是地址的搬运工。

2.1 指针指向基本数据类型

基本数据类型,比如 int、char、float、double,它们都在内存里占一块空间。指针就是指向这块空间的起始地址。

举个例子:

int a = 42;
int *p = &a;   // p 指向 a 的地址

这里 p 是个指针变量,它存的是 a 的地址。通过 *p 就能拿到 a 的值——42。我在项目中遇到过不少新手,把 p*p 搞混,调试半天才发现问题。

核心理解:

  • p 是地址(门牌号)
  • *p 是地址里存的值(屋里的人)
  • &a 是取变量 a 的地址

不同类型的指针,指向不同类型的数据。int * 只能指向 int 变量,char * 只能指向 char 变量。为什么?因为指针知道它指向的数据占几个字节。int 占4字节,char 占1字节,指针做加减运算时,步长不一样。

指针类型 指向的数据类型 步长(字节)
int * int 4
char * char 1
float * float 4
double * double 8

2.2 指针的赋值与修改

指针的赋值,说白了就是让指针指向一个新的地址。你可以让指针指向另一个变量,也可以让它指向 NULL。

int x = 10, y = 20;
int *ptr;

ptr = &x;   // ptr 指向 x
printf("%d\n", *ptr);  // 输出 10

ptr = &y;   // ptr 改为指向 y
printf("%d\n", *ptr);  // 输出 20

看到了吗?指针本身是可以被重新赋值的。它今天指向 x,明天可以指向 y。我个人习惯在指针赋值时,先确认目标地址是否有效。有一次我在项目中调试一个通信协议,就是因为指针指向了错误的地址,导致数据全部错位——排查了整整一个下午。

我的小技巧:

给指针赋值时,养成先初始化的习惯。比如:int *p = NULL; 然后再赋有效地址。这样万一忘了赋值,至少不会乱指。

还有一种情况,指针指向数组元素:

int arr[3] = {1, 2, 3};
int *p = arr;      // 指向数组首元素,等价于 &arr[0]
p++;               // 指向 arr[1]
*p = 100;          // 把 arr[1] 改成 100

指针的加减运算,实际上是在地址上跳步。跳多少?看指针类型。int * 跳4字节,char * 跳1字节。这个特性在遍历数组时特别好用。

2.3 空指针与野指针

这两个概念,我建议你刻在脑子里。空指针和野指针,是C语言里最常见的坑,没有之一。

空指针

空指针就是指向地址0的指针。在C语言里,用 NULL 宏表示。空指针的意思是:「这个指针当前不指向任何有效对象」。

int *p = NULL;

// 使用前必须检查
if (p != NULL) {
    *p = 100;  // 安全
} else {
    printf("指针为空,不能使用\n");
}

我曾经在一个嵌入式项目中,因为没检查空指针,直接解引用,导致系统跑飞。从那以后,我养成了「用指针前先判空」的习惯。说白了,这就是个保命操作。

警告:

对空指针解引用(即 *p 操作)会导致程序崩溃。在嵌入式系统中,可能直接触发硬件异常。务必在使用前判空。

野指针

野指针更可怕。它指向一个随机的、无效的地址。野指针不是 NULL,它有一个值,但这个值是垃圾值。你根本不知道它指向哪里。

野指针的常见来源:

  • 指针未初始化
  • 指针指向已释放的内存(悬空指针)
  • 指针越界访问
int *p;          // 未初始化,野指针
*p = 10;         // 危险!不知道写到哪里去了

int *q = malloc(sizeof(int));
free(q);
*q = 20;         // 危险!q 指向的内存已释放

我记得有一次,团队里一个同事在代码里忘了初始化指针,结果程序运行时好时坏。查了两天,最后发现是野指针在作怪。你想想看,野指针指向的地址可能是随机的,今天运气好没出事,明天换个环境就崩了。

避坑指南:

  • 指针声明时立即初始化:int *p = NULL;
  • 释放内存后,立即将指针置 NULL:free(p); p = NULL;
  • 不要返回局部变量的地址
  • 使用指针前,先判空

2.4 知识体系图

下面这张图,把指针与变量的核心关系梳理了一遍。建议你多看几遍,把逻辑理清楚。

指针与变量核心知识体系 指针 指向基本数据类型 赋值与修改 空指针与野指针 int * char * float * 指向新变量 指向数组元素 空指针 (NULL) 野指针(未初始化) 核心原则:初始化、判空、不越界

2.5 总结

指针与变量的关系,其实就三件事:指向谁、怎么改、别乱指。指向基本数据类型时,类型要匹配;赋值修改时,注意地址有效性;空指针和野指针,是必须时刻提防的敌人。

我个人习惯在写代码时,每声明一个指针,就立刻初始化。哪怕暂时不知道指向哪里,也先给个 NULL。这样后续使用前判空,就能避免大部分问题。嗯,这招我用了十几年,没出过事。

最后提醒一句:

指针不是洪水猛兽,它只是地址的载体。你把它当工具,它就是你手里的利器;你轻视它,它就会给你挖坑。多写、多练、多排查,慢慢就熟了。


公众号:蓝海资料掘金营,微信deep3321