【C 指针深度解析】从内存寻址到数据结构:千行代码构建指针知识体系 附带总结知识点表格 + 本人手写源码

一、指针知识全景图:为什么说指针是 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
  • 双指针逆序:startend分别指向首尾,相向移动
  • 指针与下标混合使用,灵活选择访问方式

场景 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);
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值