第一章:指针基础——内存地址、定义与初始化、取地址与解引用、指针大小
大家好,我是你们的老朋友。今天咱们正式开讲指针。说实话,指针这东西,我当年学的时候也绕了好一阵子。但一旦搞明白了,你会发现它其实就是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字节就够用了。所以,做嵌入式开发时,一定要先搞清楚目标平台的地址宽度。
本章知识体系
下面这张图帮你梳理一下本章的核心逻辑:
好,第一章的内容就到这里。记住:指针就是地址,地址就是门牌号。搞明白这个,后面的一切都好办。
公众号:蓝海资料掘金营,微信deep3321