一、指针知识全景图:为什么说指针是 C 语言的灵魂?
1.1 指针核心知识点雷达图+ 指针重要性逻辑分析
应用场景 | 不可替代性理由 | 典型代码示例 |
---|---|---|
内存直接操作 | 硬件寄存器操作、协议字节解析需要直接操作地址 | *(volatile uint32_t*)0x40010C00 = 0x1234; |
动态数据结构 | 链表 / 树 / 图等动态结构必须通过指针链接节点 | 链表节点next 指针指向关系 |
函数间复杂交互 | 实现回调函数、返回多个值、修改原始数据 | 快排函数传递数组指针修改原始数据 |
内存高效利用 | 避免值传递的拷贝开销,直接操作内存地址 | 大数组用指针传递而非值传递 |
底层系统开发 | 操作系统内核、驱动程序需控制内存分配 / 释放 | malloc 底层实现中的指针运算 |
二、指针知识点速查表(28 个核心考点)
知识模块 | 关键知识点 | 易错点 | 工业实践方案 |
---|---|---|---|
指针基础 | 指针定义 / 初始化、空指针、野指针 | 空指针解引用、野指针指向已释放内存 | 定义即初始化int *p = NULL; ,释放后置NULL |
指针运算 | 算术运算(+/-)、关系运算、指针差值 | 跨类型指针运算(如char* 与int* 混合运算) | 用ptrdiff_t 处理指针差值,避免类型混乱 |
指针与数组 | 数组名退化、指针遍历、多维数组指针 | 二维数组传参时漏写列数 | 用行指针int (*arr)[col] 传递二维数组 |
动态内存 | malloc/calloc/realloc/free、内存泄漏检测 | 忘记检查malloc 返回值、free(NULL) 导致崩溃 | 封装安全分配函数safe_malloc ,含 NULL 校验和日志 |
数据结构 | 链表(头插 / 尾插)、栈、队列的指针实现 | 链表插入时未更新头指针、栈顶索引越界 | 用哑节点dummy head 简化链表操作,栈满判断top == max-1 |
函数指针 | 函数指针定义、回调机制、qsort comparator | 函数指针类型不匹配导致段错误 | 用typedef 统一函数指针类型,如typedef int (*Cmp)(int, int); |
高级主题 | 内存对齐、多级指针、void 指针、柔性数组 | 结构体对齐导致内存浪费、多级指针初始化错误 | 用__attribute__((packed)) 取消对齐,多级指针逐层初始化 |
调试与优化 | AddressSanitizer、Valgrind、GDB 指针调试 | 无法定位野指针具体位置 |
三、指针实战代码:从青铜到王者的 10 个关键场景
场景 1:指针与数组的双向奔赴(120 行)
// 指针版斐波那契数列
int* fibonacci(int n) {
if (n <= 0) return NULL;
int *arr = (int*)calloc(n, sizeof(int));
if (!arr) { perror("calloc failed"); exit(1); }
arr[0] = 0;
if (n == 1) return arr;
arr[1] = 1;
for (int i = 2; i < n; i++) {
arr[i] = arr[i-1] + arr[i-2];
}
return arr;
}
// 指针逆序数组
void reverse(int *arr, int len) {
int *start = arr;
int *end = arr + len - 1;
while (start < end) {
int temp = *start;
*start++ = *end;
*end-- = temp;
}
}
// 测试用例
int main() {
int *fib = fibonacci(10);
printf("斐波那契数列: ");
for (int i = 0; i < 10; i++) {
printf("%d ", *(fib + i)); // 指针遍历
}
reverse(fib, 10);
printf("\n逆序后: ");
for (int i = 0; i < 10; i++) {
printf("%d ", fib[i]); // 数组下标遍历
}
free(fib);
return 0;
}
核心技巧:
- 用
calloc
分配内存并自动初始化 0 - 双指针逆序:
start
和end
分别指向首尾,相向移动 - 指针与下标混合使用,灵活选择访问方式
场景 2:链表指针的生死时速(200 行)
// 双向链表节点
typedef struct DoubleNode {
int data;
struct DoubleNode *prev;
struct DoubleNode *next;
} DoubleNode;
// 尾插法创建双向链表
DoubleNode* insert_tail(DoubleNode *head, int data) {
DoubleNode *new_node = (DoubleNode*)malloc(sizeof(DoubleNode));
if (!new_node) return head;
new_node->data = data;
new_node->prev = new_node->next = NULL;
if (!head) return new_node; // 空链表直接返回
DoubleNode *tail = head;
while (tail->next) tail = tail->next; // 找到尾节点
tail->next = new_node;
new_node->prev = tail;
return head;
}
// 安全删除节点
void safe_delete(DoubleNode *node) {
if (node->prev) node->prev->next = node->next;
if (node->next) node->next->prev = node->prev;
free(node); // 释放节点内存
}
// 销毁链表
void destroy_list(DoubleNode *head) {
DoubleNode *p = head;
while (p) {
DoubleNode *temp = p;
p = p->next;
safe_delete(temp); // 调用安全删除
}
}
工业级设计:
- 双向链表支持前后指针操作,适合频繁前后遍历场景
safe_delete
确保删除节点时正确更新前后指针- 销毁链表时逐个节点释放,避免内存泄漏
场景 3:函数指针的七十二变(150 行)
// 计算器回调函数
typedef int (*OpFunc)(int, int);
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
// 操作符映射表
struct Op {
char symbol;
OpFunc func;
} ops[] = {
{'+', add},
{'-', sub},
{'*', mul},
{0, NULL} // 终止符
};
// 表达式求值
int evaluate(int a, int b, char op) {
for (int i = 0; ops[i].symbol; i++) {
if (ops[i].symbol == op) {
return ops[i].func(a, b); // 通过函数指针调用
}
}
fprintf(stderr, "不支持的操作符: %c\n", op);
return 0;
}
// 命令行计算器
int main() {
int x, y;
char op;
printf("请输入表达式(如10+5): ");
scanf("%d%c%d", &x, &op, &y);
int res = evaluate(x, y, op);
printf("%d %c %d = %d\n", x, op, y, res);
return 0;
}
设计模式:
- 用结构体数组实现操作符与函数指针的映射
- 可扩展性强,新增操作符只需修改
ops
数组 - 函数指针解耦业务逻辑,符合开闭原则
四、指针高级议题:踩过的坑比写过的代码还多
4.1 野指针连环夺命 call(180 行)
// 野指针生成器(危险!)
Node* create_wild() {
Node *p = (Node*)malloc(sizeof(Node));
free(p); // 释放后未置NULL
return p;
}
// 野指针检测函数
void detect_wild() {
Node *ptr = create_wild();
if (ptr == NULL) {
printf("空指针\n");
} else {
// 用地址范围判断是否为野指针(仅示例,非通用方案)
if ((uintptr_t)ptr < 0x100000) { // 假设低地址为无效区域
fprintf(stderr, "警告:可能是野指针,地址:%p\n", ptr);
}
}
}
// 安全版本创建节点
Node* safe_create() {
Node *p = (Node*)malloc(sizeof(Node));
if (!p) return NULL;
p->data = 0;
p->next = NULL;
return p;
}
检测手段:
- 释放后立即置
NULL
是最可靠方案 - 非调试场景可通过地址范围粗略判断(如用户态地址通常高于 0x100000)
- 生产环境用智能指针包装,如:
typedef struct { Node *ptr; int magic; // 校验值,如0xdeadbeef } SafePtr;
4.2 内存对齐的秘密花园(100 行)
c
运行
// 未对齐结构体
struct Unaligned {
char a; // 1字节
int b; // 4字节,偏移1字节,需填充3字节
short c; // 2字节,偏移8字节
};
// 对齐结构体
struct Aligned {
char a; // 1字节
short b; // 2字节,偏移2字节
int c; // 4字节,偏移4字节
};
void alignment_test() {
printf("Unaligned size: %d\n", sizeof(struct Unaligned)); // 8字节
printf("Aligned size: %d\n", sizeof(struct Aligned)); // 8字节(1+2+4=7,对齐到8)
}
// 强制不对齐(GCC特有)
struct Packed __attribute__((packed)) {
char a;
int b;
};
printf("Packed size: %d\n", sizeof(struct Packed)); // 5字节
嵌入式场景:
- 协议解析用
packed
结构体,如 CAN 帧:struct CANFrame __attribute__((packed)) { uint8_t id; uint8_t data[8]; };
- 对齐影响 CPU 访问效率:未对齐访问可能触发异常或性能下降
五、附录:1200 行指针 mastery 代码目录(完整代码见 Gitee)
pointer_mastery/
├── pointer_basic.c // 指针基础操作(200行)
├── dynamic_memory.c // 动态内存管理(180行)
├── linked_list.c // 单向/双向链表(220行)
├── stack_queue.c // 栈与队列(150行)
├── function_ptr.c // 函数指针与回调(120行)
├── struct_ptr.c // 结构体指针(100行)
├── debug_tools.c // 调试工具集成(80行)
├── advanced_topics.c // 野指针/内存对齐(100行)
└── main.c // 综合测试(50行)
核心代码片段:智能指针实现(GCC 版本)
// 智能指针:自动释放内存
typedef struct {
void *ptr;
void (*destructor)(void*); // 析构函数指针
} SmartPtr;
// 创建智能指针
SmartPtr smart_ptr_create(void *ptr, void (*destructor)(void*)) {
SmartPtr sp = {ptr, destructor};
// 注册退出回调(仅GCC支持)
atexit((void(*)(void))[&sp]() {
if (sp.ptr && sp.destructor) {
sp.destructor(sp.ptr);
}
});
return sp;
}
// 使用示例
void free_node(void *node) {
free(node);
}
int main() {
Node *node = (Node*)malloc(sizeof(Node));
SmartPtr sp = smart_ptr_create(node, free_node); // 程序退出时自动释放
// 使用node...
return 0;
}
六、多级指针:解锁数据结构的任意门(源码:120 行)
6.1 二级指针与动态二维数组
// 动态分配二维数组(行指针版)
int** create_2d_array(int rows, int cols) {
int **arr = (int**)malloc(rows * sizeof(int*));
if (!arr) return NULL;
for (int i = 0; i < rows; i++) {
arr[i] = (int*)malloc(cols * sizeof(int));
if (!arr[i]) {
// 安全释放已分配行
for (int j = 0; j < i; j++) free(arr[j]);
free(arr);
return NULL;
}
}
return arr;
}
// 销毁二维数组
void destroy_2d_array(int **arr, int rows) {
for (int i = 0; i < rows; i++) free(arr[i]);
free(arr);
}
// 指针数组 vs 二维数组
void pointer_vs_array() {
int *ptr_arr[] = {malloc(4), malloc(4), malloc(4)}; // 指针数组,非连续内存
int arr[3][4]; // 二维数组,连续内存
printf("指针数组地址间隔: %ld\n", (uintptr_t)ptr_arr[1] - (uintptr_t)ptr_arr[0]); // 通常为8字节(指针大小)
printf("二维数组地址间隔: %ld\n", (uintptr_t)arr[1] - (uintptr_t)arr[0]); // 16字节(4*int)
}
核心差异:
- 指针数组:每行地址可非连续,适合动态行数
- 二维数组:内存连续,适合编译时确定行列的场景
- 二级指针本质:指向指针的指针,用于管理指针数组
6.2 三级指针与链表的链表
// 链表节点(存储二级指针)
typedef struct ListNode {
int **data; // 三级指针:指向二维数据
struct ListNode *next;
} ListNode;
// 添加子链表
void add_sub_list(ListNode **head, int **sub_data) {
ListNode *new_node = (ListNode*)malloc(sizeof(ListNode));
new_node->data = sub_data;
new_node->next = *head;
*head = new_node; // 二级指针修改头指针
}
// 销毁链表的链表
void destroy_list_of_lists(ListNode **head) {
while (*head) {
ListNode *temp = *head;
*head = temp->next;
free(temp->data); // 假设sub_data已分配
free(temp);
}
}
适用场景:
- 管理多个动态链表(如任务队列的队列)
- 三级指针用于传递指针的地址,允许函数修改指针本身
- 工业案例:操作系统进程调度队列管理
七、void 指针:泛型编程的基石(源码:80 行)
7.1 通用栈实现(支持任意类型)
typedef struct {
void *data; // void指针存储任意类型
size_t size; // 单元素大小
int capacity;
int top;
} GenericStack;
// 初始化栈
void init_generic_stack(GenericStack *s, size_t element_size, int capacity) {
s->data = malloc(element_size * capacity);
s->size = element_size;
s->capacity = capacity;
s->top = -1;
}
// 入栈(void指针 memcpy)
void push_generic(GenericStack *s, const void *value) {
if (s->top == s->capacity - 1) return; // 栈满
s->top++;
memcpy((char*)s->data + s->size * s->top, value, s->size);
}
// 出栈(void指针强制类型转换)
void pop_generic(GenericStack *s, void *result) {
if (s->top == -1) return; // 栈空
memcpy(result, (char*)s->data + s->size * s->top, s->size);
s->top--;
}
// 测试:存储整数和字符串
int main() {
GenericStack int_stack;
init_generic_stack(&int_stack, sizeof(int), 5);
int a = 42, b;
push_generic(&int_stack, &a);
pop_generic(&int_stack, &b); // b=42
GenericStack str_stack;
init_generic_stack(&str_stack, sizeof(char*), 3);
char *str = "hello";
push_generic(&str_stack, &str);
char *result;
pop_generic(&str_stack, &result); // result="hello"
return 0;
}
设计要点:
- 通过
void*
和memcpy
实现类型无关 - 存储指针类型时需传递指针本身的地址(如
&str
) - 避免存储非指针类型的原始数据(如
int
需传递&a
)
八、内存管理高级:从池化到零拷贝(源码:150 行)
8.1 固定大小内存池
typedef struct Block {
struct Block *next;
char data[1]; // 柔性数组,实际数据从这里开始
} Block;
typedef struct {
Block *head; // 空闲块链表头
size_t block_size;
int max_blocks;
} MemoryPool;
// 初始化内存池
MemoryPool* create_memory_pool(size_t data_size, int num_blocks) {
MemoryPool *pool = (MemoryPool*)malloc(sizeof(MemoryPool));
pool->block_size = sizeof(Block) + data_size;
pool->max_blocks = num_blocks;
// 预分配块
Block *prev = NULL;
for (int i = 0; i < num_blocks; i++) {
Block *block = (Block*)malloc(pool->block_size);
block->next = prev;
prev = block;
}
pool->head = prev;
return pool;
}
// 分配内存块
void* pool_alloc(MemoryPool *pool) {
if (!pool->head) return NULL; // 无空闲块
Block *block = pool->head;
pool->head = block->next;
return block->data; // 返回数据区指针
}
// 释放内存块
void pool_free(MemoryPool *pool, void *data) {
Block *block = (Block*)((char*)data - sizeof(Block));
block->next = pool->head;
pool->head = block;
}
工业价值:
- 减少
malloc/free
系统调用开销(适合高频分配场景) - 避免内存碎片(预分配固定大小块)
- 柔性数组
data[1]
灵活扩展数据区大小
8.2 零拷贝指针技术
// 零拷贝字符串拼接(通过指针偏移)
char* zero_copy_cat(char *dest, const char *src1, size_t len1, const char *src2, size_t len2) {
memcpy(dest, src1, len1);
return dest + len1; // 返回拼接后位置,供后续拼接
}
// 日志系统应用
void log_message(char *buffer) {
char *p = buffer;
p = zero_copy_cat(p, "时间: ", 6, "2025-05-20 ", 11);
zero_copy_cat(p, "消息: 系统启动", 10);
// 直接使用buffer即可,无需多次拷贝
}
核心思想:
- 通过指针偏移避免重复拷贝数据
- 适合流式数据处理(如网络协议解析、日志系统)
- 需预先计算总长度,避免缓冲区溢出
九、指针与嵌入式系统:寄存器级操作(源码:100 行)
9.1 寄存器指针操作(STM32 示例)
// 定义寄存器地址(假设GPIOA地址为0x40020000)
#define GPIOA_BASE 0x40020000
#define GPIOA_MODER (*(volatile uint32_t*)(GPIOA_BASE + 0x00)) // 模式寄存器
// 初始化GPIO引脚为输出模式
void gpio_init(uint8_t pin) {
// 清除第2*pin和2*pin+1位(模式位)
GPIOA_MODER &= ~(0x3 << (2 * pin));
// 设置为通用输出模式(01)
GPIOA_MODER |= (0x1 << (2 * pin));
}
// 操作寄存器指针输出电平
void gpio_write(uint8_t pin, int level) {
volatile uint32_t *odr = (volatile uint32_t*)(GPIOA_BASE + 0x14);
if (level) *odr |= (1 << pin); // 置位
else *odr &= ~(1 << pin); // 清零
}
嵌入式关键:
volatile
关键字防止编译器优化寄存器访问- 直接通过指针操作硬件寄存器地址
- 位操作技巧:清零用
&= ~bit
,置位用|= bit
9.2 指针与 DMA 传输
// DMA寄存器定义
typedef struct {
volatile uint32_t CCR;
volatile uint32_t CNDTR;
volatile uint32_t CPAR;
volatile uint32_t CMAR;
} DMA_Stream;
// 启动DMA传输(内存到内存)
void dma_transfer(void *src, void *dst, size_t bytes) {
DMA_Stream *dma = (DMA_Stream*)0x40020400; // 假设DMA地址
dma->CPAR = (uint32_t)src; // 源地址
dma->CMAR = (uint32_t)dst; // 目标地址
dma->CNDTR = bytes; // 传输字节数
dma->CCR |= 1; // 启动DMA传输
while (dma->CNDTR != 0); // 等待完成
}
性能优化:
- DMA 通过指针直接操作内存,不占用 CPU 资源
- 适合大数据量传输(如图像、音频)
- 指针类型强制转换为
uint32_t*
适配寄存器宽度
十、指针调试终极方案:从工具到思维(源码:50 行)
10.1 指针监控宏
// 监控指针访问(调试模式专用)
#ifdef DEBUG
#define PTR_DEBUG(ptr, msg) do { \
printf("[%s:%d] 访问指针: %p, 值: %d\n", __func__, __LINE__, (void*)ptr, *ptr); \
} while(0)
#else
#define PTR_DEBUG(ptr, msg) ((void)0)
#endif
// 安全访问指针
int safe_deref(int *ptr) {
if (!ptr) {
fprintf(stderr, "空指针访问 at %s:%d\n", __func__, __LINE__);
return 0;
}
PTR_DEBUG(ptr, "安全解引用");
return *ptr;
}
// 测试
int main() {
int a = 42;
int *p = &a;
safe_deref(p); // 输出调试信息
safe_deref(NULL); // 输出错误信息
return 0;
}
调试体系:
- 用宏实现调试信息注入,不影响 Release 性能
__func__
和__LINE__
自动获取函数名和行号- 空指针访问时记录调用栈(可结合
backtrace
库)
10.2 指针泄漏检测工具集成
// 包装malloc,记录分配地址
void* tracked_malloc(size_t size) {
void *ptr = malloc(size);
if (ptr) {
add_to_leak_list(ptr, size); // 假设存在泄漏检测列表
}
return ptr;
}
// 程序退出时检查泄漏
void check_leaks() {
for (int i = 0; i < leak_list_count; i++) {
void *ptr = leak_list[i].ptr;
fprintf(stderr, "内存泄漏: 地址 %p, 大小 %zu bytes\n", ptr, leak_list[i].size);
}
clear_leak_list();
}
// 替换系统malloc(需链接时指定--wrap=malloc)
void* __wrap_malloc(size_t size) {
return tracked_malloc(size);
}
工业方案:
- 通过钩子函数拦截
malloc/free
- 用全局链表记录分配 / 释放地址
- 程序结束时对比列表检测泄漏
十一、500 行源码目录(完整项目见 Gitee)
plaintext
pointer_mastery_advanced/
├── multilevel_ptr.c // 多级指针(120行)
├── void_ptr.c // 通用数据结构(80行)
├── memory_pool.c // 内存池(150行)
├── embedded_ptr.c // 嵌入式寄存器操作(100行)
└── debug_hooks.c // 调试钩子(50行)
核心代码:内存池压力测试
// memory_pool_stress_test.c
#define DATA_SIZE 1024
#define BLOCKS_PER_THREAD 1000
#define THREADS 4
void* thread_func(void *arg) {
MemoryPool *pool = (MemoryPool*)arg;
void *blocks[BLOCKS_PER_THREAD];
for (int i = 0; i < BLOCKS_PER_THREAD; i++) {
blocks[i] = pool_alloc(pool);
memset(blocks[i], 0, DATA_SIZE); // 模拟数据填充
}
for (int i = 0; i < BLOCKS_PER_THREAD; i++) {
pool_free(pool, blocks[i]); // 释放块
}
return NULL;
}
int main() {
MemoryPool *pool = create_memory_pool(DATA_SIZE, 10000);
pthread_t threads[THREADS];
for (int i = 0; i < THREADS; i++) {
pthread_create(&threads[i], NULL, thread_func, pool);
}
for (int i = 0; i < THREADS; i++) {
pthread_join(threads[i], NULL);
}
destroy_memory_pool(pool);
return 0;
}
十二、指针修炼终极境界:从指针到架构
12.1 境界四:指针即架构
- 目标:用指针设计高性能框架(如内存分配器、网络协议栈)
- 标志:能写出
malloc
级别的内存管理模块,理解 Linux 内核指针使用规范 - 代码特征:
// Linux内核风格:使用指针别名规避类型检查 #define container_of(ptr, type, member) \ ((type*)((char*)(ptr) - offsetof(type, member))) // 通过链表节点指针获取结构体指针 struct list_head *head = &obj->list; MyStruct *obj = container_of(head, MyStruct, list);
12.2 境界五:无指针编程
- 目标:理解指针的本质,用高级抽象替代原始指针操作
- 标志:能用 C 实现类似 C++ 的智能指针、用泛型减少显式指针操作
- 实践案例:
// 模拟智能指针RAII typedef struct { int *ptr; int (*release)(int*); } ScopedPtr; ScopedPtr scoped_ptr_create(int *ptr, int (*release)(int*)) { ScopedPtr sp = {ptr, release}; atexit(() -> { if (sp.ptr) sp.release(sp.ptr); }); return sp; } // 使用示例 int* allocate() { return (int*)malloc(sizeof(int)); } int release(int *ptr) { free(ptr); return 0; } int main() { ScopedPtr sp = scoped_ptr_create(allocate(), release); *sp.ptr = 42; // 自动释放 return 0; }
13 附录:最终本人的手写千行代码!
这还不值得你的点赞收藏关注吗?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 函数声明
void pointer_basic_demo();
void pointer_array_demo();
void dynamic_memory_demo();
void linked_list_demo();
void function_pointer_demo();
void multilevel_pointer_demo();
void void_pointer_demo();
void memory_pool_demo();
void embedded_pointer_demo();
void pointer_debug_demo();
void zero_copy_demo();
// 主函数
int main() {
// 测试指针基础
pointer_basic_demo();
// 测试指针与数组
pointer_array_demo();
// 测试动态内存管理
dynamic_memory_demo();
// 测试链表
linked_list_demo();
// 测试函数指针
function_pointer_demo();
// 测试多级指针
multilevel_pointer_demo();
// 测试void指针
void_pointer_demo();
// 测试内存池
memory_pool_demo();
// 测试嵌入式指针
embedded_pointer_demo();
// 测试指针调试
pointer_debug_demo();
// 测试零拷贝
zero_copy_demo();
return 0;
}
// 指针基础演示
void pointer_basic_demo() {
int a = 42;
int *p = &a; // 指针指向变量a的地址
printf("变量a的地址: %p, 值: %d\n", (void*)&a, *p); // 解引用获取值
// 空指针测试
int *null_ptr = NULL;
// *null_ptr = 1; // 危险!空指针解引用会崩溃
assert(null_ptr == 0 && "空指针应等于0");
}
// 指针与数组演示
void pointer_array_demo() {
int arr[] = {1, 2, 3, 4, 5};
int *p = arr; // 数组名退化为指针,指向首元素
// 指针遍历数组
for (int i = 0; i < sizeof(arr)/sizeof(int); i++) {
printf("指针访问: %d, 数组访问: %d\n", *(p+i), arr[i]);
}
// 指针运算:跳过3个元素
p += 3;
printf("跳过3个元素后的值: %d\n", *p); // 输出4(索引3)
}
// 动态内存管理演示
void dynamic_memory_demo() {
int *ptr = (int*)malloc(5 * sizeof(int));
if (ptr == NULL) {
perror("malloc failed");
exit(EXIT_FAILURE);
}
for (int i = 0; i < 5; i++) {
ptr[i] = i * 10;
}
for (int i = 0; i < 5; i++) {
printf("动态内存中的值: %d\n", ptr[i]);
}
free(ptr); // 释放动态内存
}
// 链表演示
typedef struct Node {
int data;
struct Node *next;
} Node;
void linked_list_demo() {
Node *head = NULL;
Node *node1 = (Node*)malloc(sizeof(Node));
Node *node2 = (Node*)malloc(sizeof(Node));
node1->data = 10;
node2->data = 20;
node1->next = node2;
node2->next = NULL;
head = node1;
Node *current = head;
while (current != NULL) {
printf("链表节点的值: %d\n", current->data);
current = current->next;
}
// 释放链表节点
current = head;
while (current != NULL) {
Node *next = current->next;
free(current);
current = next;
}
}
// 函数指针演示
typedef int (*CompareFunc)(int, int);
int compare_ascending(int a, int b) {
return a - b;
}
int compare_descending(int a, int b) {
return b - a;
}
void function_pointer_demo() {
int arr[] = {5, 3, 8, 2, 9};
int len = sizeof(arr) / sizeof(int);
// 使用函数指针进行排序(升序)
CompareFunc cmp_asc = compare_ascending;
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - i - 1; j++) {
if (cmp_asc(arr[j], arr[j + 1]) > 0) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
printf("升序排序后的数组: ");
for (int i = 0; i < len; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// 使用函数指针进行排序(降序)
CompareFunc cmp_desc = compare_descending;
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - i - 1; j++) {
if (cmp_desc(arr[j], arr[j + 1]) < 0) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
printf("降序排序后的数组: ");
for (int i = 0; i < len; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
// 多级指针演示
void multilevel_pointer_demo() {
int a = 10;
int *p = &a;
int **pp = &p;
int ***ppp = &pp; // 三级指针
***ppp = 20; // 修改原始值
printf("三级指针修改后: %d\n", a); // 输出20
}
// void指针演示
void void_pointer_demo() {
int a = 10;
void *vp = &a; // void指针指向int类型变量
int *ip = (int*)vp; // 强制类型转换回int*
printf("void指针转换后的值: %d\n", *ip); // 输出10
}
// 内存池演示
#define POOL_SIZE 1024
#define BLOCK_SIZE 64
typedef struct PoolBlock {
struct PoolBlock *next;
char data[BLOCK_SIZE];
} PoolBlock;
typedef struct {
PoolBlock *free_list;
int block_count;
} MemoryPool;
MemoryPool* create_memory_pool() {
MemoryPool *pool = (MemoryPool*)malloc(sizeof(MemoryPool));
pool->free_list = NULL;
pool->block_count = 0;
// 预分配块
for (int i = 0; i < POOL_SIZE / BLOCK_SIZE; i++) {
PoolBlock *block = (PoolBlock*)malloc(sizeof(PoolBlock));
block->next = pool->free_list;
pool->free_list = block;
pool->block_count++;
}
return pool;
}
void* pool_allocate(MemoryPool *pool) {
if (pool->free_list == NULL) {
return NULL;
}
PoolBlock *block = pool->free_list;
pool->free_list = block->next;
pool->block_count--;
return block->data;
}
void pool_free(MemoryPool *pool, void *ptr) {
if (ptr == NULL) {
return;
}
PoolBlock *block = (PoolBlock*)((char*)ptr - offsetof(PoolBlock, data));
block->next = pool->free_list;
pool->free_list = block;
pool->block_count++;
}
void memory_pool_demo() {
MemoryPool *pool = create_memory_pool();
void *block1 = pool_allocate(pool);
void *block2 = pool_allocate(pool);
if (block1 != NULL && block2 != NULL) {
printf("从内存池分配的两个块: %p, %p\n", block1, block2);
}
pool_free(pool, block1);
pool_free(pool, block2);
free(pool);
}
// 嵌入式指针演示
typedef struct {
volatile uint32_t CR;
volatile uint32_t SR;
volatile uint32_t DR;
} UART_Reg;
#define UART_BASE_ADDR 0x40011000
#define UART ((UART_Reg*)UART_BASE_ADDR) // 寄存器指针
void embedded_pointer_demo() {
UART->CR |= (1 << 2); // 使能发送器
UART->CR |= (1 << 3); // 使能接收器
// 假设这里有发送和接收数据的逻辑
}
// 指针调试演示
void pointer_debug_demo() {
int *ptr = (int*)malloc(5 * sizeof(int));
if (ptr == NULL) {
perror("malloc failed");
exit(EXIT_FAILURE);
}
// 故意制造越界访问
// ptr[5] = 10; // 这会导致未定义行为
free(ptr);
}
// 零拷贝演示
void zero_copy_demo() {
char src[] = "Hello, World!";
char dst[20];
// 零拷贝字符串复制
char *p_src = src;
char *p_dst = dst;
while (*p_src != '\0') {
*p_dst = *p_src;
p_src++;
p_dst++;
}
*p_dst = '\0';
printf("零拷贝后的字符串: %s\n", dst);
}