第一章:指针基础——内存地址、定义与初始化、取地址与解引用、指针大小

大家好,我是你们的老朋友。今天咱们正式开讲指针。说实话,指针这东西,我当年学的时候也绕了好一阵子。但一旦搞明白了,你会发现它其实就是C语言的灵魂。

好,咱们不废话,直接进入正题。

1.1 内存地址:每个变量都有自己的门牌号

你想想看,计算机的内存就像一栋巨大的公寓楼。每个房间都有一个唯一的门牌号。这个门牌号,就是内存地址。

变量呢?变量就是住在这个房间里的房客。比如你写:

int a = 10;

编译器会为 a 分配一个房间(通常是4个字节),然后在这个房间里放上数字10。这个房间的门牌号,就是 &a

核心概念:内存地址是字节在内存中的编号。每个字节都有一个唯一的地址。地址从0开始,一直往上排。

我在项目中遇到过一个问题:有个同事调试时打印变量地址,发现每次运行地址都不一样。他以为程序出bug了。其实这是现代操作系统的地址空间布局随机化(ASLR)在起作用。嗯,这个后面讲动态内存时还会提到。

1.2 指针的定义与初始化:别让指针成为野指针

指针是什么?说白了,指针就是一个变量,只不过它存的是地址,而不是普通数值。

定义指针的语法很简单:

int *p;   // p 是一个指向 int 类型的指针
char *q;  // q 是一个指向 char 类型的指针
void *r;  // r 是一个无类型指针(后面会讲)

这里有个坑,我刚开始学的时候也犯过。你看下面这两行:

int* p, q;   // 你以为 p 和 q 都是指针?
// 实际上:p 是指针,q 是普通 int 变量!

为什么会这样?因为 * 是跟变量名结合的,不是跟类型结合的。我个人习惯这样写:

int *p;
int *q;   // 每个指针单独一行,清晰明了

指针初始化特别重要。不初始化的指针,我们叫它「野指针」。野指针指向哪里?不知道。可能是系统关键数据区,也可能是别的程序的内存。你往里面写数据,轻则段错误,重则系统崩溃。

警告:永远不要使用未初始化的指针!我曾经在调试一个嵌入式设备时,就因为一个野指针把整个系统的中断向量表给覆盖了,设备直接死机。排查了整整两天才找到原因。

正确的初始化方式:

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

// 或者初始化为 NULL
int *q = NULL;  // 表示指针不指向任何有效地址

1.3 取地址符 & 与解引用符 *

这两个符号是指针操作的核心。咱们一个一个说。

取地址符 &:获取变量的内存地址。

int x = 42;
int *ptr = &x;   // ptr 拿到了 x 的门牌号

解引用符 *:通过地址访问变量本身。

int x = 42;
int *ptr = &x;

*ptr = 100;      // 通过 ptr 修改 x 的值
printf("%d\n", x);  // 输出 100

你看,*ptr 就相当于 x。你操作 *ptr,就是在操作 x 本身。

小技巧:我教学生时经常说:把 & 想象成「我要这个变量的地址」,把 * 想象成「我要这个地址里的内容」。这样记,不容易混淆。

这里有个容易搞混的地方:定义指针时的 * 和 解引用时的 * 是两回事。

int *p;    // 定义时:声明 p 是一个指针
*p = 10;   // 使用时:解引用 p,往它指向的位置写 10

嗯,这个区别很重要。定义时的 * 是类型声明的一部分,使用时的 * 是操作符。

1.4 指针的大小:不是所有指针都一样大

这个问题我经常被问到:「指针占几个字节?」

答案是:取决于平台。

平台 指针大小 说明
32位系统 4字节 地址总线32位,可寻址4GB
64位系统 8字节 地址总线64位,可寻址巨大空间
嵌入式8位MCU 2字节或4字节 取决于具体架构

你想想看,指针存的是地址。地址有多大?在32位系统上,地址是32位的,所以指针就是4字节。在64位系统上,地址是64位的,指针就是8字节。

我用 sizeof 验证一下:

printf("int* 的大小: %zu 字节\n", sizeof(int*));
printf("char* 的大小: %zu 字节\n", sizeof(char*));
printf("void* 的大小: %zu 字节\n", sizeof(void*));

有意思的是,不管指针指向什么类型,在同一个平台上它们的大小都是一样的。为什么?因为地址就是地址,不管这个地址里存的是 int 还是 char,地址本身占的字节数是一样的。

重要:指针的大小只跟平台有关,跟指针指向的数据类型无关。int*char* 在同一个平台上大小相同。

我在嵌入式开发中遇到过一个问题:有个同事在8位单片机上用 int* 指针,结果发现指针只占2字节。他以为代码写错了。其实是因为那个单片机的地址空间只有64KB,2字节就够用了。所以,做嵌入式开发时,一定要先搞清楚目标平台的地址宽度。

本章知识体系

下面这张图帮你梳理一下本章的核心逻辑:

第一章:指针基础 · 知识体系 指针基础 内存地址 每个字节有唯一编号 变量 = 房间 + 门牌号 定义与初始化 int *p = &a; 避免野指针! & 与 * 操作符 & 取地址 * 解引用 指针的大小 32位: 4字节 64位: 8字节 核心要点 指针是存地址的变量 · 类型决定步长 · 大小由平台决定

好,第一章的内容就到这里。记住:指针就是地址,地址就是门牌号。搞明白这个,后面的一切都好办。


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