第一部分:指针到底是什么?
指针 = 一张"地址小纸条"
- 普通变量:家里放了一把钥匙(值)。
- 指针变量:手里拿着一张写着"钥匙放在哪"的纸条(地址)。
看下面这张图(最经典的指针解释):

图里关键点:
var变量放在地址0x7ffa0757dd4,里面存着10ptr是指针,它自己存的不是10,而是var的地址0x7ffa0757dd4*ptr(解引用) = 顺着纸条找到钥匙,拿到10
一句话总结 :
指针变量里存的是别人的内存地址 ,用 * 才能拿到真正的值。
第二部分:结构体是什么?
结构体 = 一个"文件袋",里面可以放不同类型的东西。
看下面这张图(结构体在内存里的真实样子):

图里说明:
struct example里有char a、int b、char c- 因为CPU喜欢"对齐"(一次读4字节),编译器会自动在中间加padding(填充)
- 所以整个结构体占12字节,而不是6字节(这在内核驱动里非常重要!)
第三部分:指针 + 结构体 = Linux驱动里的"王炸"
最常用的是指向结构体的指针!
看这张超级清晰的图:

图里解释:
ptr存的是整个结构体的起始地址(1080)- 通过
ptr->name、ptr->roll就能直接访问里面的字段 - 这就是驱动里
struct my_device *dev = ...的真实样子!
再看一张更直观的(指针指向结构体):

驱动里的实际例子
c
struct my_device {
int id; // 设备编号
char name[32]; // 设备名字
};
struct my_device dev; // 普通结构体变量
struct my_device *p = &dev; // 指针指向它(驱动里99%都用这种)
p->id = 1; // 等价于 (*p).id = 1
实例练习
在 Ubuntu 新建 understand_lab.c,复制下面代码运行:
c
#include <stdio.h>
struct student {
int id;
char name[20];
};
int main() {
struct student s = { .id = 100, .name = "Tesha" };
struct student *p = &s; // 指针指向结构体
printf("直接访问:id=%d, name=%s\n", s.id, s.name);
printf("通过指针访问:id=%d, name=%s\n", p->id, p->name);
printf("结构体地址:%p\n", (void*)&s);
printf("指针存的地址:%p\n", (void*)p);
return 0;
}
编译运行:
bash
gcc -Wall -g understand_lab.c -o understand_lab
./understand_lab
输出如下:

第四部分:C语言指针与结构体核心符号对比表(驱动开发专用版)
| 概念/符号 | 含义(白话解释) | 适用对象 | 示例代码 | 内存本质(地址视角) | 驱动开发注意点(避免Panic) | 等价写法 / 口诀 |
|---|---|---|---|---|---|---|
| 普通变量 | 直接存放"值"(钥匙) | 变量本体 | int a = 42; |
地址里存的是值本身 | 几乎不用(驱动里全是指针) | - |
| 指针变量 | 存放"地址纸条"(指向别人的地址) | 任何类型 | int *p = &a; |
地址里存的是另一个变量的地址 | 必须先判断 if (!p),否则空指针Panic |
"纸条" |
| & (取地址) | "给我这个变量的地址" | 变量本体 | p = &a; 或 struct student *sp = &s; |
返回变量的起始地址 | 只用于赋值给指针变量 | "拿纸条" |
| *** ** (星号) | ①声明指针 ②解引用(打开纸条看内容) | ①声明时 ②使用时 | int *p; *p = 100; |
①声明类型 ②顺着地址取值/改值 | 忘记解引用或多解引用会导致野指针 | "*声明=指针,*使用=打开看" |
| . (点) | 访问结构体本体的成员 | 结构体变量(非指针) | struct student s; s.id = 100; |
结构体起始地址 + 成员偏移 | 驱动里几乎不用(指针太多) | "本体用点" |
| -> (箭头) | 访问指向结构体的指针的成员 | 结构体指针 | struct student *p; p->id = 100; |
先解引用指针得到结构体地址,再加偏移 | 驱动里90% 用这个(filp->private_data 等) | "指针用箭头" |
| 结构体 | 把多个不同类型数据打包成一个"文件袋" | 自定义类型 | struct my_dev { int id; char name[32]; }; |
连续内存块(可能有padding对齐) | 必须用 container_of 从成员反推整个结构体 |
"文件袋" |
| container_of | 从成员指针反推出整个结构体指针 | 内核链表/嵌入式结构体 | dev = container_of(pos, struct my_dev, list); |
ptr - offsetof(结构体, 成员) |
驱动灵魂!不掌握这个写不了任何现代驱动 | "从零件找到整车" |