指针进阶

数组与指针

  • 指针数组与数组指针

    • 数组:int arr[10];

      表示arr为有10个元素的数组,每个元素的类型为int

    • 指针数组:int* arr[10];

      表示arr为有10个元素的数组,每个元素的类型为int*,即指针数组

  • 二级指针

    • 概念:存放一级指针的地址的指针变量

      注:指针变量类型的理解与区分:

      • int* - 指向 * 前的 int 类型的指针变量
      • int** - 指向 * 前的 int* 类型的指针变量

函数指针、函数指针数组

  • 函数指针

    概念:指向函数的指针(存放函数地址的指针)

    定义方法:int(*pfunction)(int, int) = &function;(类型为 int (*)(int, int))

  • 函数指针数组

    概念:存放函数指针的数组

    定义方法:int(*arr[10])();(数组元素的类型为 int (*)())

  • 指向函数指针数组的指针

    这种就属于嵌套了上面的概念,其他嵌套也一样,仔细分析可以知道这是存放函数指针数组地址的指针

    注:试分析:void (*function(int, void(*)(int)))(int); 的含义

    它实际上等价于下面的代码,在实际开发中,尽量不要使用上面复杂的写法

    typedef void (*pfunction)(int); // 定义pfunction类型
    pfunction function(int, pfunction); // 声明了function函数,返回值和参数都是函数指针

指针的左右法则

  • 步骤

    • 找到核心标识符:从声明中最内侧的变量名或函数名开始分析(这是解析的起点)
    • 先右后左解析
      • 先看标识符右边的符号(如 [] 表示数组,() 表示函数)
      • 再看标识符左边的符号(如 * 表示指针)
      • 重复 “右→左” 的顺序,逐步向外层扩展,直到解析完整个声明
    • 遇到括号优先处理:括号会改变解析顺序,先解析括号内的内容
  • 示例解析

    以复杂声明 int *(*func[10])(char *) 为例,用右左法则拆解

    • 找到核心标识符 func 声明的主体是 func,从它开始解析

    • 先看右边:[10] func 右边是 [10],表示 func 是一个 “包含 10 个元素的数组”

    • 再看左边:* 数组左边有 *,表示这个数组的元素是 “指针”(即 func 是一个 “指针数组”)

    • 继续向外,看右边的 (char *) 指针数组外侧有 (char *),表示这些指针指向 “函数”(因为函数声明用 () 表示),且该函数接受一个 char * 类型的参数

    • 最后看左边的 int * 函数左边是 int *,表示这个函数的返回值是 “int * 类型的指针”

    • 最终结论

      int *(*func[10])(char *) 表示: func 是一个包含 10 个元素的数组,数组中的每个元素都是函数指针,这些指针指向的函数接受 char * 类型参数,并返回 int * 类型指针


指针传参

  • 一维数组传参

    // 传递实参int arr[10];的方法
    void test(int arr[10]) {}
    void test(int arr[]) {}
    void test(int* arr) {}
    
    // 传递实参int* arr[20];的方法
    void test(int* arr[20]) {}
    void test(int* arr[]) {}
    void test(int** arr) {}
  • 二维数组传参

    // 传递实参int arr[3][5];的方法
    void test(int arr[3][5]) {}
    void test(int arr[][5]) {}
    void test(int (*arr)[5]) {}
  • 指针传参思考

    Q:思考:当函数的形参为一级指针时,可以接收的实参有哪些?

    A:一级指针、一维数组

    Q:思考:当函数的形参为二级指针时,可以接收的实参有哪些?

    A:二级指针、一级指针数组

  • 回调函数

    • 概念

      一个通过函数指针调用的函数。如果把函数的指针作为参数传递给另一个函数,当这个指针被用来调用其指向的函数时,我们就说这是回调函数

      注:

      • 回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另一方调用的,用于对于该事件或条件的响应
      • 这种机制,我们称之为“回调函数机制”
    • 实例

      // 使用回调函数编写冒泡排序函数
      void bubble_sort(void* ptr, size_t count, size_t size, int (*cmp)(const void* e1, const void* e2)) {
          int num = 0, judge = 1;
          for (; num < count - 1 && judge; num++) {
              int i = 0;
              judge = 0; // 标志位:假设已经有序
              for (i = 0; i < count - 1 - num; i++) {
                  if (cmp((char*) ptr + size * i, (char*) ptr + size * (i + 1)) > 0) {
                      int j = 0;
                      judge = 1;
                      for (j = 0; j < size; j++) {
                          *((char*) ptr + i * size + j) = *((char*) ptr + i * size + j) ^ *((char*) ptr + (i + 1) * size + j);
                          *((char*) ptr + (i + 1) * size + j) =
                                  *((char*) ptr + i * size + j) ^ *((char*) ptr + (i + 1) * size + j);
                          *((char*) ptr + i * size + j) = *((char*) ptr + i * size + j) ^ *((char*) ptr + (i + 1) * size + j);
                      }
                  }
              }
          }
      }
« 指针 ← 返回列表 字符串处理的库函数介绍 »