Skip to content

指针进阶

本章将深入探讨指针的高级用法,包括多级指针、函数指针、指针与数组的高级应用等。

多级指针

c
/*
 * 多级指针
 */

#include <stdio.h>

int main(void)
{
    int num = 10;
    
    /* 一级指针:指向普通变量 */
    int *p1 = &num;
    
    /* 二级指针:指向一级指针 */
    int **p2 = &p1;
    
    /* 三级指针:指向二级指针 */
    int ***p3 = &p2;
    
    printf("=== 多级指针 ===\n");
    printf("num = %d\n", num);
    printf("*p1 = %d\n", *p1);
    printf("**p2 = %d\n", **p2);
    printf("***p3 = %d\n", ***p3);
    
    printf("\n=== 地址关系 ===\n");
    printf("&num = %p\n", (void*)&num);
    printf("p1 = %p\n", (void*)p1);
    printf("*p2 = %p\n", (void*)*p2);
    printf("**p3 = %p\n", (void*)**p3);
    
    /* 通过多级指针修改值 */
    **p2 = 20;
    printf("\n通过**p2修改后: num = %d\n", num);
    
    ***p3 = 30;
    printf("通过***p3修改后: num = %d\n", num);
    
    /* 实际应用:动态二维数组 */
    printf("\n=== 动态二维数组 ===\n");
    
    int rows = 3, cols = 4;
    
    /* 分配行指针数组 */
    int **matrix = (int**)malloc(rows * sizeof(int*));
    
    /* 分配每行 */
    for (int i = 0; i < rows; i++) {
        matrix[i] = (int*)malloc(cols * sizeof(int));
    }
    
    /* 初始化 */
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = i * cols + j;
        }
    }
    
    /* 打印 */
    printf("动态二维数组:\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%2d ", matrix[i][j]);
        }
        printf("\n");
    }
    
    /* 释放 */
    for (int i = 0; i < rows; i++) {
        free(matrix[i]);
    }
    free(matrix);
    
    return 0;
}

函数指针

基本用法

c
/*
 * 函数指针基础
 */

#include <stdio.h>

/* 普通函数 */
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { return b != 0 ? a / b : 0; }

int main(void)
{
    /* 声明函数指针 */
    int (*operation)(int, int);
    
    /* 指向add函数 */
    operation = add;
    printf("add(10, 5) = %d\n", operation(10, 5));
    
    /* 指向subtract函数 */
    operation = subtract;
    printf("subtract(10, 5) = %d\n", operation(10, 5));
    
    /* 使用typedef简化 */
    typedef int (*MathOp)(int, int);
    
    MathOp op1 = add;
    MathOp op2 = multiply;
    
    printf("\nop1(10, 5) = %d\n", op1(10, 5));
    printf("op2(10, 5) = %d\n", op2(10, 5));
    
    /* 函数指针数组 */
    MathOp operations[] = {add, subtract, multiply, divide};
    char *names[] = {"加", "减", "乘", "除"};
    
    printf("\n=== 计算器 ===\n");
    for (int i = 0; i < 4; i++) {
        printf("10 %s 5 = %d\n", names[i], operations[i](10, 5));
    }
    
    return 0;
}

回调函数

c
/*
 * 回调函数
 */

#include <stdio.h>
#include <stdlib.h>

/* 比较函数类型 */
typedef int (*CompareFunc)(const void*, const void*);

/* 整数比较函数 */
int compare_int(const void *a, const void *b)
{
    return (*(int*)a - *(int*)b);
}

/* 降序比较 */
int compare_desc(const void *a, const void *b)
{
    return (*(int*)b - *(int*)a);
}

/* 使用回调函数的排序 */
void bubble_sort(void *arr, size_t count, size_t size, CompareFunc compare)
{
    char *base = (char*)arr;
    char *temp = (char*)malloc(size);
    
    for (size_t i = 0; i < count - 1; i++) {
        for (size_t j = 0; j < count - 1 - i; j++) {
            void *a = base + j * size;
            void *b = base + (j + 1) * size;
            
            if (compare(a, b) > 0) {
                /* 交换 */
                memcpy(temp, a, size);
                memcpy(a, b, size);
                memcpy(b, temp, size);
            }
        }
    }
    
    free(temp);
}

/* 处理数组元素的回调 */
typedef void (*ProcessFunc)(int*);

void double_value(int *n) { *n *= 2; }
void square_value(int *n) { *n *= *n; }
void negate_value(int *n) { *n = -*n; }

void process_array(int arr[], int len, ProcessFunc process)
{
    for (int i = 0; i < len; i++) {
        process(&arr[i]);
    }
}

int main(void)
{
    int arr[] = {5, 2, 8, 1, 9, 3};
    int len = sizeof(arr) / sizeof(arr[0]);
    
    printf("原数组: ");
    for (int i = 0; i < len; i++) printf("%d ", arr[i]);
    
    /* 使用回调函数排序 */
    bubble_sort(arr, len, sizeof(int), compare_int);
    printf("\n升序: ");
    for (int i = 0; i < len; i++) printf("%d ", arr[i]);
    
    bubble_sort(arr, len, sizeof(int), compare_desc);
    printf("\n降序: ");
    for (int i = 0; i < len; i++) printf("%d ", arr[i]);
    
    /* 使用qsort(标准库) */
    int arr2[] = {5, 2, 8, 1, 9, 3};
    qsort(arr2, len, sizeof(int), compare_int);
    printf("\n\nqsort结果: ");
    for (int i = 0; i < len; i++) printf("%d ", arr2[i]);
    
    /* 处理数组 */
    int arr3[] = {1, 2, 3, 4, 5};
    printf("\n\n原数组: ");
    for (int i = 0; i < 5; i++) printf("%d ", arr3[i]);
    
    process_array(arr3, 5, double_value);
    printf("\n翻倍后: ");
    for (int i = 0; i < 5; i++) printf("%d ", arr3[i]);
    
    return 0;
}

函数指针作为返回值

c
/*
 * 函数指针作为返回值
 */

#include <stdio.h>

/* 运算函数 */
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }

/* 函数指针类型 */
typedef int (*Operation)(int, int);

/* 根据操作符返回对应的函数 */
Operation get_operation(char op)
{
    switch (op) {
        case '+': return add;
        case '-': return subtract;
        case '*': return multiply;
        default: return NULL;
    }
}

int main(void)
{
    char ops[] = {'+', '-', '*'};
    
    for (int i = 0; i < 3; i++) {
        Operation op = get_operation(ops[i]);
        if (op != NULL) {
            printf("10 %c 5 = %d\n", ops[i], op(10, 5));
        }
    }
    
    return 0;
}

指针与多维数组

c
/*
 * 指针与多维数组
 */

#include <stdio.h>

int main(void)
{
    int arr[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };
    
    printf("=== 二维数组的指针理解 ===\n");
    
    /* arr 是指向第一行的指针 */
    printf("arr = %p\n", (void*)arr);
    printf("arr[0] = %p\n", (void*)arr[0]);
    printf("&arr[0][0] = %p\n", (void*)&arr[0][0]);
    
    /* arr + 1 指向第二行 */
    printf("\narr + 1 = %p\n", (void*)(arr + 1));
    printf("arr[1] = %p\n", (void*)arr[1]);
    
    /* *(arr + 1) 是第二行的首元素地址 */
    printf("\n*(arr + 1) = %p\n", (void*)*(arr + 1));
    printf("&arr[1][0] = %p\n", (void*)&arr[1][0]);
    
    /* *(*(arr + 1) + 2) 是 arr[1][2] */
    printf("\n*(*(arr + 1) + 2) = %d\n", *(*(arr + 1) + 2));
    printf("arr[1][2] = %d\n", arr[1][2]);
    
    /* 使用指针遍历二维数组 */
    printf("\n=== 指针遍历二维数组 ===\n");
    
    /* 方法1:指向行的指针 */
    int (*row_ptr)[4] = arr;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%2d ", row_ptr[i][j]);
        }
        printf("\n");
    }
    
    /* 方法2:指向元素的指针 */
    printf("\n");
    int *elem_ptr = &arr[0][0];
    for (int i = 0; i < 3 * 4; i++) {
        printf("%2d ", elem_ptr[i]);
        if ((i + 1) % 4 == 0) printf("\n");
    }
    
    /* 方法3:使用指针运算 */
    printf("\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%2d ", *(*(arr + i) + j));
        }
        printf("\n");
    }
    
    return 0;
}

复杂指针声明

c
/*
 * 理解复杂指针声明
 */

#include <stdio.h>

/*
 * 指针声明阅读规则(右左法则):
 * 1. 从变量名开始
 * 2. 先向右读,再向左读
 * 3. 遇到括号就跳到括号内
 */

int main(void)
{
    /* 简单指针 */
    int *p1;                    /* p1是指向int的指针 */
    
    /* 指针数组 */
    int *p2[5];                 /* p2是数组,包含5个指向int的指针 */
    
    /* 数组指针 */
    int (*p3)[5];               /* p3是指针,指向包含5个int的数组 */
    
    /* 函数指针 */
    int (*p4)(int);             /* p4是指针,指向返回int、参数为int的函数 */
    
    /* 函数指针数组 */
    int (*p5[5])(int);          /* p5是数组,包含5个函数指针 */
    
    /* 返回指针的函数 */
    int *func(int);             /* func是函数,返回指向int的指针 */
    
    /* 返回函数指针的函数 */
    int (*func2(int))(int);     /* func2是函数,参数为int,返回函数指针 */
    
    /* 复杂示例 */
    int (*(*p6)[5])(int);       /* p6是指针,指向包含5个函数指针的数组 */
    
    printf("复杂指针声明示例已编译通过\n");
    
    /* 实际示例 */
    int arr[5] = {1, 2, 3, 4, 5};
    
    /* 数组指针 */
    int (*arr_ptr)[5] = &arr;
    printf("\n数组指针: (*arr_ptr)[0] = %d\n", (*arr_ptr)[0]);
    
    /* 指针数组 */
    int a = 1, b = 2, c = 3;
    int *ptr_arr[3] = {&a, &b, &c};
    printf("指针数组: *ptr_arr[0] = %d\n", *ptr_arr[0]);
    
    /* 函数指针 */
    int add(int x, int y) { return x + y; }
    int (*func_ptr)(int, int) = add;
    printf("函数指针: func_ptr(3, 4) = %d\n", func_ptr(3, 4));
    
    return 0;
}

指针与const

c
/*
 * 指针与const的进阶用法
 */

#include <stdio.h>

int main(void)
{
    int a = 10;
    int b = 20;
    
    /* 1. 指向常量的指针 */
    const int *p1 = &a;
    /* *p1 = 100; */  /* 错误:不能修改指向的值 */
    p1 = &b;          /* 正确:可以修改指针本身 */
    
    /* 2. 常量指针 */
    int * const p2 = &a;
    *p2 = 100;        /* 正确:可以修改指向的值 */
    /* p2 = &b; */    /* 错误:不能修改指针本身 */
    
    /* 3. 指向常量的常量指针 */
    const int * const p3 = &a;
    /* *p3 = 200; */  /* 错误 */
    /* p3 = &b; */    /* 错误 */
    
    /* 实际应用 */
    printf("=== 实际应用 ===\n");
    
    /* 字符串处理函数参数 */
    /* size_t strlen(const char *s); */
    /* 参数是const char*,保证函数不会修改字符串 */
    
    /* 返回常量指针 */
    const int* get_constant(void);
    
    /* 结构体成员指针 */
    struct Config {
        const char *name;     /* 指向常量字符串 */
        int * const values;   /* 常量指针,始终指向同一地址 */
    };
    
    printf("const指针用法示例完成\n");
    
    return 0;
}

指针安全

c
/*
 * 指针安全编程
 */

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    printf("=== 指针安全编程 ===\n\n");
    
    /* 1. 初始化指针 */
    int *p1 = NULL;  /* 始终初始化为NULL */
    
    /* 2. 使用前检查 */
    if (p1 != NULL) {
        printf("*p1 = %d\n", *p1);
    } else {
        printf("p1是空指针\n");
    }
    
    /* 3. 释放后置NULL */
    int *p2 = (int*)malloc(sizeof(int));
    if (p2 != NULL) {
        *p2 = 100;
        printf("分配成功: %d\n", *p2);
        free(p2);
        p2 = NULL;  /* 释放后立即置NULL */
    }
    
    /* 4. 避免野指针 */
    int *wild;
    /* printf("%d", *wild); */  /* 未定义行为 */
    
    /* 5. 避免悬空指针 */
    int *dangling;
    {
        int local = 10;
        dangling = &local;
    }  /* local被销毁 */
    /* printf("%d", *dangling); */  /* 未定义行为 */
    
    /* 6. 检查分配是否成功 */
    int *large = (int*)malloc(1000000000000);
    if (large == NULL) {
        printf("大内存分配失败\n");
    }
    
    /* 7. 使用assert */
    #include <assert.h>
    int *p3 = (int*)malloc(sizeof(int));
    assert(p3 != NULL);  /* 如果为NULL,程序终止 */
    free(p3);
    
    printf("\n指针安全检查完成\n");
    
    return 0;
}

小结

本章学习了:

  • 多级指针:二级指针、三级指针、动态二维数组
  • 函数指针:声明、使用、回调函数、函数指针数组
  • 指针与多维数组:理解二维数组的指针表示
  • 复杂指针声明:右左法则解读
  • 指针与const:const的各种组合用法
  • 指针安全:避免野指针、悬空指针、内存泄漏

掌握指针进阶知识,可以更好地理解和使用C语言的强大功能。