云计算百科
云计算领域专业知识百科平台

C语言:指针

回顾

 /*************************************************************************
   > File Name:   demo01.c
   > Author:       久念昕
   > Description:  
   > Created Time: 2025年07月28日 星期一 09时07分38秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 /**
  * 指向一维数组的指针
  */
 int t_p1()
 {
     // 创建一个一维数组
     int arr[] = {10,20,30,40,50};
     // 计算数组大小
     int len = sizeof(arr) / sizeof(arr[0]);  
 ​
     // 创建一个数组指针指向一维数组arr
     int (*p)[len] = &arr;
     // 借助数组指针遍历数组
     for (int i = 0; i < len; i++)
    {
         // p 指向 arr这个数组,p存储了arr这个数组的地址
         // 如果通过指针访问数组:*p *和[]在一起,[]的优先级大于*
         printf("%-4d", (*p)[i]);
    }
     printf("\\n");
 ​
 }
 ​
 /**
  * 指向二维数组的指针
  */
 int t_p2()
 {
     // 创建一个二维数组
     int arr[][3] = {
        {10,20,30},
        {100,200,300},
        {1000,2000,3000}
    };
     // 获取行和列的容量
     int row_len = sizeof(arr) / sizeof(arr[0]);
     int col_len = sizeof(arr[0]) / sizeof(arr[0][0]);
 ​
     // 方式1,二维数组指针指向二维数组   不推荐
     int (*p)[][3] = &arr;
 ​
     // 遍历数组
     for (int i = 0; i < row_len; i++)
    {
         for (int j = 0; j < col_len; j++)
        {
             printf("%-6d", (*p)[i][j]);
        }
    }
     printf("\\n");
 ​
     // 方式2,一维数组指针指向二维数组,本质上是一体维数组指针指向二维数组的行(默认首行)推荐
     // &arr:获取该二维数组的地址,范围作用于整个数组
     // arr:数组名默认指向第一个元素,这里就是行,默认首行,范围作用于整个行,等价于 &arr[0]
     // 数组参与指针运算,会降级为指针
     int (*p1)[3] = arr;
 ​
     for (int i = 0; i < row_len; i++)
    {
         for (int j = 0; j < col_len; j++)
        {
             printf("%-6d",p1[i][j]);
             printf("%-6d",(*(p1+i))[j]);
             printf("%-6d",*(p1[i]+j));// 列偏移
             printf("%-6d",*(*(p1+i)+j));
        }
    }
     printf("\\n");
     
 }
 ​
 int main(int argc,char *argv[])
 {
    t_p1();
    t_p2();
     
 }
 ​

指针

数组指针与指针数组

数组指针
指针和数组中符号优先级

 ()> [] > *

通过指针引用二维数组
表示形式含义地址/值
arr 二维数组名,指向一维数组arr[0],0行首地址 2000
arr[0],*(arr+0),*arr 0行0列元素地址,数组降级为指针 2000
arr + 1, &arr[1] 1行首地址 2008
arr[1],*(arr + 1) 1行0列元素arr[1][0]的地址 2008
arr[1]+2,*(arr+1)+2,&arr[1][2] 1行2列元素arr[1][2]的地址 2012
*(arr[1]+2),*(*(arr+1)+2),arr[1][2] 1行2列元素arr[1][2]的值 元素值为13

注意:二维数组中,数组整体的地址值 == 数组中0行元素的地址值 == 数组中0行0列元素的地址值

案例
案例1
  • 需求:用指向元素的指针变量输出二维数组元素的值

  • 代码:

 /*************************************************************************
   > File Name:   demo02.c
   > Author:       久念昕
   > Description:  
   > Created Time: 2025年07月28日 星期一 10时46分40秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 int main(int argc,char *argv[])
 {
     // 定义一个二维数组
     int arr[3][4] = {10,20,30,40,100,200,300,400,1000,2000,3000,4000};
 ​
     // 定义一个指针变量,用来指向数组中的元素
     int *p = /* *(arr+0) |*/ *arr /* | arr[0] */;
 ​
     // 获取元素个数 = 行容量 * 列容量
     
     int len = (sizeof(arr)/sizeof(arr[0])) * (sizeof(arr[0])/sizeof(arr[0][0]));
 ​
     // 使用单层for循环遍历二维数组,列
     for (; p < arr[0] + len; p++)
    {
        // 每四个一行 p1 – p2 = (p1地址 – p2地址) / sizeof(type)
        if ((p – arr[0]) % 4 == 0 && p != arr[0]) printf("\\n");
 ​
        printf("%-6d", *p);
    }
 ​
     printf("\\n");
 ​
     return 0;
 }
 ​

案例2:
  • 需求:数组指针- 输出二维数组任意行任意列的元素的值

  • 代码:

     /*************************************************************************
       > File Name:   demo03.c
       > Author:       久念昕
       > Description:  
       > Created Time: 2025年05月21日 星期三 10时57分26秒
      ************************************************************************/
     ​
     #include <stdio.h>
     ​
     int main(int argc,char *argv[])
     {
         // 定义一个二维数组
         int arr[3][4] = {1,3,5,7,11,33,55,77,111,333,555,777};
     ​
         // 创建一个数组指针指向二维数组
         int (*p)[4] = arr; // 二维数组中的第一个元素就是首行 int (*p)[3][4]
     ​
         // 创建两个变量,接收控制台输入的行和列
         int row, col;
     ​
         printf("请输入行号和列号:\\n");
         scanf("%d,%d",&row,&col);
     ​
         printf("arr[%d][%d]=%d,%d,%d,%d\\n",row,col,*(*(p+row)+col),(*(p+row))[col],*(p[row]+col),p[row][col]);
     ​
         return 0;
     }
     ​

指针数组

定义:指针数组是一个数组,数组中每一个元素都是一个指针。

特点:

  • 先有指针,后有数组

  • 指针数组的本质是一个数组,只是数组中的每一个元素是指针。

语法:

 数据类型 *数组名[容量];

案例:

 /*************************************************************************
   > File Name:   demo03.c
   > Author:       久念昕
   > Description:  
   > Created Time: 2025年07月28日 星期一 11时31分18秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 int main(int argc,char *argv[])
 {
     // 定义三个变量
     int a = 10, b = 20, c = 30;
 ​
     // 定义指针数组:先有指针,后有数组
     int *arr[3] = {&a, &b, &c};
 ​
     // 获取大小
     int len = sizeof(arr) / sizeof(arr[0]);
 ​
     // 遍历数组
     for (int i = 0; i < len; i++)
    {
         printf("%-3d", *arr[i]);
    }
 ​
     printf("\\n");
 ​
     return 0;
 }
 ​

建议:我们一般使用指针数组处理字符串,后续专门讲解。

数组指针与指针数组的区别
对比项指针数组数组指针
定义 数组元素均为指针的数组 指向一个完整数组的指针
存储内容 存储多个指针,每个元素指向不同内存地址 存储单个指针,指向一个完整的数组(首地址)
内存分配 每个指针元素独立分配内存,可能分散 指向的数组内存连续,指针本身存储数组首地址
语法示例 int *arr[5](元素为5个int*指针) int (*arr)[5](指向5个int的数组的指针)
访问方式 通过下标访问指针元素,再解引用: *arr[i] 先解引用指针得到数组,再访问元素: (*arr)[i]
使用场景 管理多个独立指针(如字符串数组、动态结构体数组) 操作多维数组(如传递二维数组的行指针)
内存布局 [ptr1] → 数据1 [ptr2] → 数据2 … ptr → [数据1][数据2]…
示例代码 int a=1, b=2;int *arr[] = {&a, &b}; int arr[2][3] = {1,2,3,4,5,6};int (*ptr)[3] = arr;

字符数组与字符指针

字符串实现

在C语言中,表示一个字符串有以下两种方式:

① 数组形式:用字符数组存放一个字符串

② 指针形式:用字符指针指向一个字符串

案例

 /*************************************************************************
   > File Name:   demo04.c
   > Author:       久念昕
   > Description:  
   > Created Time: 2025年07月28日 星期一 14时15分31秒
  ************************************************************************/
 ​
 #include <stdio.h>
 ​
 /**
  * 方式1:使用字符数组实现字符串
  */
 void str_test1()
 {
     // 定义一个伪字符串
     char str[] = "I LOVE YOU";
     // 数组名是一个常量,也就是不支持赋值
     // str = "YUE QIAN"; // 编译报错,常量不支持修改,替代方案:strcpy(str,"YUE QIAN");
     
     printf("%s\\n", str); // 数组在传参时,会被降级为指针
 }
 ​
 /**
  * 方式2:使用字符指针指向字符串
  */
 void str_test2()
 {
     // 定义一个伪字符串
     char *str = "I LOVE YOU"; // 指针str指向一个字符串常量
     // 改变str的指向
     // str = "YUE QIAN";
     printf("%s\\n", str);
 }
 ​
 int main(int argc,char *argv[])
 {
     str_test1();
     str_test2();
 ​
     char arr[200];
     char *str = arr; // 局部变量,如果未初始化,默认是随机值,如果是指针变量,地址值就是随机
     printf("请输入一个字符串:\\n");
     scanf("%s", str);
     printf("%s\\n", str);
 ​
     return 0;
 }
 ​

注意:字符数组和字符指针变量都能实现字符串的存储与运算。(字符指针—> 字符类型的指针变量)

字符数组和字符指针的联系
概念
  • 字符数组由元素组成,每个元素中存放一个字符;而字符指针(指向char类型的指针变量)中存放的是地址;

  • 只能对字符数组中的各个元素赋值,而不能用赋值语句对整个字符数组赋值。

 char arr[3] = {};   // 等价于 {'\\0'}; 等价于 {0};
 arr[2] = 'A';       // 正确,对字符数组的元素赋值
 ​
 arr = {'E','D','F'};// 错误,数组名是常量,不能对其进行整体赋值

  • 字符数组名虽然代表地址,但是数组名的值不能改变,因为数组名是常量。

char a = 'A';
char arr[50] = {};

char *p = arr; // 指针p指向数组第一个元素,p存储的是arr数组中第一个元素的地址

p = &a; // 改变指针p的指向,使其指向变量a,p存储的是a的地址

arr = &a; // 错误:数组名虽然是指针,但是数组名同时也是常量,所以不能赋值

p++; // p指向arr的第2个元素
arr+5;
*p = 'W';
printf("%c %c\\n", *p, *arr);

return 0;
}

  • 对于字符串中字符的存取,可以用下标法,也可以用指针法。

    /*************************************************************************
    > File Name: demo05.c
    > Author: 久念昕
    > Description:
    > Created Time: 2025年05月21日 星期三 14时58分00秒
    ************************************************************************/

    #include <stdio.h>

    int main(int argc,char *argv[])
    {
    // 使用两种方式创建字符串
    char str1[] = "你好,双哥哥!";
    char *str2 = "你好,豪哥哥!";// 0x11

    // 赋值测试
    // str1 = "你好,强哥哥!"; // 错误,数组一旦创建,就无法改变其值。
    str2 = "你好,帅哥哥!";// 0x12

    // 打印测试
    printf("%s,%s\\n", str1, str2);

    // 测试从控制台获取一个字符串
    // char *str;// 此时默认值是NULL,NULL对应的空间地址0x00000000,这块空间拒绝访问
    // printf("请输入一个字符串:\\n");
    // scanf("%s",str);
    // printf("输出-%s\\n",str);// 输出NULL

    // 注意:从控制台接收一个字符串只能用字符数组

    char a[] = "I LOVE YOU!";
    char *b = "I LOVE YOU!";

    printf("%c,%c\\n%c,%c\\n%s,%s\\n",a[2],*(a+2),b[2],*(b+2),a+2,b+2);// L,L L,L
    1 2

    return 0;
    }

字符串作为形参
定义
  • 实参与形参都可以是字符数组

void fun(char str[], int len) {..}
void main()
{
char str[] = "hello";
int len = sizeof(str) / sizeof(str[0]);
fun(str, len)
}

  • 实参用字符数组,形参用字符指针

void fun(char *str, int len) {..}
void main()
{
char str[] = "hello";
int len = sizeof(str) / sizeof(str[0]);
fun(str, len)
}

  • 形参和实参都是字符指针。(在函数内部不能对字符串常量中的字符做修改)

/*************************************************************************
> File Name: demo06.c
> Author: 久念昕
> Description:
> Created Time: 2025年07月28日 星期一 15时26分14秒
************************************************************************/

#include <stdio.h>

void fun(char *str, int len) {
printf("%s\\n", str);// 0x1000 str依然指向“hello"这个常量空间

// *(str+1) = 'E';// 编译错误 不能修改"hello"这个常量空间的数据

// str[2] = 'L'; // 编译错误

str = "zhangsanfeng"; // 0x2000 此时并没有改变常量空间的数据,只是改变了指针的指向

printf("%s\\n", str);
}

void main()
{
char *str = "hello"; // 0x1000 str指向的"hello"是一个常量空间,常量空间不支持修改
int len = sizeof(str) / sizeof(str[0]);
fun(str, len); // 0x1000
}

  • 实参是字符指针,形参是字符数组。(在函数内部不能对字符串常量中的字符做修改)

/*************************************************************************
> File Name: demo06.c
> Author: 久念昕
> Description:
> Created Time: 2025年07月28日 星期一 15时26分14秒
************************************************************************/

#include <stdio.h>

void fun(char str[], int len) {
printf("%s\\n", str);// 0x1000 str依然指向“hello"这个常量空间

// *(str+1) = 'E';// 编译错误 不能修改"hello"这个常量空间的数据

// str[2] = 'L'; // 编译错误

str = "zhangsanfeng"; // 此时并没有改变常量空间的数据,只是改变了指针的指向

printf("%s\\n", str);
}

void main()
{
// char str[] = {'h','e','l','l','o','\\0'}; // 这个可以看做是字符串变量,这个是支持修改元素
char *str = "hello"; // 0x1000 str指向的"hello"是一个常量空间,常量空间不支持修改
int len = sizeof(str) / sizeof(str[0]);
fun(str, len);// 0x1000
}

注意
  • 字符数组在创建的时候,会在内存中开辟内存空间,内存空间可以存放字符数据;字符指针在创建的时候,需要依赖于字符数组,字符指针在内存开辟的内存空间中,存放的是数组元素的地址。字符指针的创建依赖于字符数组,字符数组可以独立存在,而字符指针不能独立存在。

  • 字符数组可以初始化,但是不能赋值;字符指针可以初始化,也可以赋值。

    char str1[] = "hello"; // 对数组初始化
    str1 = "hi"; // 对数组赋值,此时错误

    str1[0] = 'H'; // 对数组中的元素赋值,此时正确

  • 案例
    案例1
    • 字符指针作为函数参数:用函数调用实现字符串的复制以及长度计算

    • 代码:

      /*************************************************************************
      > File Name: demo07.c
      > Author: 久念昕
      > Description:
      > Created Time: 2025年07月28日 星期一 15时50分22秒
      ************************************************************************/

      #include <stdio.h>

      /**
      * 定义一个函数,实现字符串拷贝
      * @param source 拷贝的源字符串,该字符串不能被修改
      * @param dest 需要拷贝的目标数组
      * @return 字符串的长度
      */
      int _str_cpy(const char *source, char *dest)
      {
      // 定义一个循环变量
      register int i = 0;

      // 遍历循环
      while (source[i] != '\\0')
      {
      // 实现拷贝
      *(dest + i) = *(source + i); // 等价于 dest[i] = source[i];
      i++;
      }

      // 拷贝结束,一定要给dest中插入\\0
      *(dest + i) = '\\0';

      return i;
      }

      int main(int argc,char *argv[])
      {
      char source[20],dest[20];

      printf("请输入一个字符串:\\n");
      scanf("%s", source);

      int size = _str_cpy(source, dest);

      printf("字符串:%s的长度是%d\\n", dest, size);

      return 0;
      }

    案例2
    • 需求:字符指针作为函数的参数-给定一个字符串,截取start到end之间的字符串,含头不含尾

    • 代码:

      /*************************************************************************
      > File Name: demo08.c
      > Author: 久念昕
      > Description:
      > Created Time: 2025年07月28日 星期一 16时06分51秒
      ************************************************************************/

      #include <stdio.h>

      /**
      * 定义一个函数,实现字符串的截取
      * @param source 源字符串(字符数组、字符串常量、字符指针)
      * @param start 开始位置
      * @param end 结束位置
      * @param dest 目标数组(字符数组)
      * @return 目标字符串长度
      */
      int str_substr(const char *source, int start, int end, char *dest)
      {
      register int i = 0, k = 0;

      // 遍历字符串
      while (source[i] != '\\0')
      {
      // 根据start和end截取
      if (i >= start && i < end) // 含头不含尾
      {
      *(dest + k) = *(source + i); // hello
      k++;
      }
      i++;
      }

      *(dest + k) = '\\0';

      return k;
      }

      int main(int argc,char *argv[])
      {
      char *str = "abcdefg";// cde
      char dest[26];
      int len = str_substr(str,2,5,dest);

      printf("%s,%s,%d\\n", str, dest, len);// abcdefg,cde,3

      return 0;
      }/*************************************************************************
      > File Name: demo08.c
      > Author: 冯鹏飞
      > Description:
      > Created Time: 2025年07月28日 星期一 16时06分51秒
      ************************************************************************/

      #include <stdio.h>

      /**
      * 定义一个函数,实现字符串的截取
      * @param source 源字符串(字符数组、字符串常量、字符指针)
      * @param start 开始位置
      * @param end 结束位置
      * @param dest 目标数组(字符数组)
      * @return 目标字符串长度
      */
      int str_substr(const char *source, int start, int end, char *dest)
      {
      register int i = 0, k = 0;

      // 遍历字符串
      while (source[i] != '\\0')
      {
      // 根据start和end截取
      if (i >= start && i < end) // 含头不含尾
      {
      *(dest + k) = *(source + i); // hello
      k++;
      }
      i++;
      }

      *(dest + k) = '\\0';

      return k;
      }

      int main(int argc,char *argv[])
      {
      char *str = "abcdefg";// cde
      char dest[26];
      int len = str_substr(str,2,5,dest);

      printf("%s,%s,%d\\n", str, dest, len);// abcdefg,cde,3

      return 0;
      }

    函数指针与指针函数

    指针函数

    定义:

    本质上是上函数,这个函数的返回值类型是指针,这个函数称之为指针函数。(返回值是指针的函数叫做指针函数)

    语法:

    // 写法1
    返回类型* 函数名(形参列表)
    {
    函数体;
    return 指针;
    }

    // 写法2
    返回类型 *函数名(形参列表)
    {
    函数体;
    return 指针;
    }

    举例:

    int *get(int a)
    {
    int *p = &a;
    return p;
    }

    int main()
    {
    int *a = get(5);
    printf("%d\\n", *a);
    }

    注意:

    在函数中不要直接返回一个局部变量的地址。因为函数调用完毕后,随着栈帧的回收,变量空间会销毁,使得返回的地址就不明确,此时返回的指针叫做野指针。

    解决方案:

    如果非要访问,可以给这个局部变量添加(定义的时候添加)static,可以延长它的生命周期,从而避免野指针(尽量少用,因为存在内存泄漏)

    演示案例:

    /*************************************************************************
    > File Name: demo05.c
    > Author: 久念昕
    > Description:
    > Created Time: 2025年05月22日 星期四 14时22分07秒
    ************************************************************************/

    #include <stdio.h>

    int *add(int a, int b)
    {
    static int sum;

    sum = a + b;

    return &sum;// 执行完return 作为函数作用域的布局变量sum的空间被释放
    }

    int main(int argc,char *argv[])
    {
    int *res = add(5,3); // 接收到了地址,但是地址对应的空间已经释放
    printf("%d\\n", *res);

    return 0;
    }

    案例
    • 需求:有若干个学生,每个学生有4门成绩,要求在用户输入学号(int id)后,能输出该学生的全部成绩(float scores[4]),用指针函数实现。

    • 代码:

      /*************************************************************************
      > File Name: demo09.c
      > Author: 久念昕
      > Description:
      > Created Time: 2025年07月28日 星期一 17时11分38秒
      ************************************************************************/

      #include <stdio.h>

      /**
      * 定义一个函数,要求输入学号,返回该学号对应学生的4门成绩
      * @param all:所有人的成绩传进来 查找源头
      * @param id:要检索学生的学号
      * @return id对应学生的4门成绩
      */
      float* search(float (*all)[4], int id)
      {
      // 定义一个指针变量,用来接收查询到的学生的所有成绩
      float *pt;

      pt = *(all + id);// 行偏移 {10,20,30,40}

      return pt;
      }

      int main(int argc,char *argv[])
      {
      // 准备一个二维数组,存储3个学生的成绩
      float scores[3][4] = {
      {60,70,80,90}, // 0x2000 0x2004 0x2008 0x200C
      {66,77,88,99}, // 0x2010 0x2014 0x2018 0x201C
      {61,71,81,91}
      };

      // 定义一个变量,用来接收学生学号
      int id;
      printf("请输入学生学号(0~2):\\n");
      scanf("%d", &id);
      printf("第%d个学生的成绩:\\n", id);

      // 创建一个指针,用来接收成绩
      float *p;// 0x11 –> 0x2000
      p = search(scores, id);// 0x21 –> 0x2000

      // 遍历
      for (; p < scores[id] + 4; p++)
      {
      printf("%5.2f\\t", *p);
      }
      // *(p + i)
      printf("\\n");

      return 0;
      }

    函数指针
    定义

    函数指针本质上是指针,是一个指向函数的指针。函数都有一个入口地址,所谓指向函数的指针,就是指向函数的入口地址。(这里的函数名就代表入口地址)

    函数指针存在的意义:

    • 让函数多了一种调用方式

    • 函数指针可以作为形参,可以形式调用(回调函数)

    遵循:先有函数,后有指针

    语法:

    返回类型 (*指针变量名)(形参列表);

    举例:

    int (*fun)(int a, int b);
    int (*fun)(int, int); // 有点类似于函数声明

    函数指针的初始化

    ① 定义的同时赋值

    // 函数指针需要依赖于函数,先有函数,后有指针

    // 定义一个普通函数
    int add(int a, int b) { return a + b; }

    // 定义一个函数指针,并初始化
    // 观察:函数指针的返回类型和指向的函数的返回类型一致,函数指针的形参个数、类型、位置和指向的函数的参数的一致。
    int (*p)(int a, int b) = add; // 函数指针p指向函数add,这里的add不能带(),add就表示函数的入口地址

    ② 先定义,后赋值

    // 定义一个普通函数
    int add(int a, int b) { return a + b; }

    int (*p)(int, int); // 形参列表的参数名可以省略不写

    p = add; // 此时是将add的入口地址赋值给指针p

    注意:

  • 函数指针指向的函数要和函数指针定义的返回值类型,形参列表对应,否则编译报错

  • 函数指针是指针,但不能指针运算,如p++等,没有实际意义

  • 函数指针作为形参,可以形成回调

  • 函数指针作为形参,函数调用时的实参只能是与之对应的函数名,不能带小括号()

  • 函数指针的形参列表中的变量名可以省略

  • 注意:函数不能作为函数的形参,但是指向函数的函数指针是可以作为函数的形参的。

    案例
    • 需求:求a,b两个数的最大值

    • 代码:

      /*************************************************************************
      > File Name: demo01.c
      > Author: 久念昕
      > Description:
      > Created Time: 2025年07月29日 星期二 09时02分35秒
      ************************************************************************/

      #include <stdio.h>

      /**
      * 定义一个函数,求两个数的最大值
      */
      int get_max(int a, int b)
      {
      return a > b ? a : b;
      }

      int main(int argc,char *argv[])
      {
      // 定义测试数据
      int a = 3, b = 4, max;

      // 直接调用函数
      max = get_max(a, b);

      printf("%d,%d中的最大值是:%d\\n",a,b,max);

      // 定义一个函数指针
      int (*p)(int, int) = get_max;

      // 间接调用函数:方式1
      max = p(a,b);
      printf("%d,%d中的最大值是:%d\\n",a,b,max);

      // 间接调用函数:方式2
      max = (*p)(a,b); // () > [] > *
      printf("%d,%d中的最大值是:%d\\n",a,b,max);

      return 0;
      }

    回调函数
    定义

    回调函数就是一个通过函数指针调用的函数。如果你把函数的指针作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时。我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

    简单来说,就是使用函数指针作为函数的形参,这种函数就被称作回调函数。

    为什么要用回调函数

    因为可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。

    简而言之,回调函数就是允许用户把需要调用的方法的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。

    案例

    /*************************************************************************
    > File Name: demo02.c
    > Author: 久念昕
    > Description:
    > Created Time: 2025年07月29日 星期二 09时25分56秒
    ************************************************************************/

    #include <stdio.h>

    /**
    * 回调函数1
    */
    int callback_1(int a)
    {
    printf("hello, this is callback_1:a=%d\\n", a);

    return a;
    }

    /**
    * 回调函数2
    */
    int callback_2(int b)
    {
    printf("hello, this is callback_2:b=%d\\n", b);

    return b;
    }

    /**
    * 回调函数3
    */
    int callback_3(int c)
    {
    printf("hello, this is callback_3:c=%d\\n", c);

    return c;
    }

    /**
    * 实现回调函数(形参是函数指针的函数)
    */
    int handle(int x, int (*callback)(int))
    {
    printf("日志:开始执行任务!\\n");
    int res = callback(x);
    printf("日志:执行结果:%d\\n",res);
    printf("日志:结束执行任务!\\n");
    }

    int main(int argc,char *argv[])
    {
    handle(100,callback_1);
    handle(200,callback_2);
    handle(300,callback_3);

    return 0;
    }

    运行结果:

    二级指针

    定义

    二级指针(多重指针)用于储存一级指针的地址,需要两次解引用才能访问原始数据。其他多重指针的用法类似,但实际开发中最常见的指针是二级指针。

    int a = 10; // a是普通变量,也就是原始数据
    int *p = &a; // 一级指针,p指向a,解引用1次就可以获取a的值
    printf("%d\\n", *p); // 10

    int **w = &p; // 二级指针,w指向p,解引用2次就可以获取a的值
    printf("%d\\n", **w);// 10

    int ***k = &w; // 三级指针,k指向w,解引用3次就可以获取a的值
    printf("%d\\n", ***k); // 10 int a1 = ***k; int *a2 = **k; int **a3 = *k; int ***a4 = k;

    语法

    数据类型 **指针变量名 = 指针数组的数组名 | 一级指针的地址

    特点

    ① 与指针数组的等效性 二级指针与指针数组在某些时候存在等效性,但与二维数组不等效。二维数组名是数组指针类型,如int (*)[3],而非二级指针。

    // 指针数组
    int arr[] = {11,22,33};
    int *arr_[] = {&arr[0],&arr[1],&arr[2]};

    // 二级指针接收指针数组
    char *str[3] = {"abc","aaa034","12a12"};
    char **p = str; // p:数组首地址,行地址,默认0行 *p:列地址,默认0行0列 **p:列元素

    /*************************************************************************
    > File Name: demo03.c
    > Author: 久念昕
    > Description:
    > Created Time: 2025年07月29日 星期二 10时27分05秒
    ************************************************************************/

    #include <stdio.h>

    int main(int argc,char *argv[])
    {
    char *str[3] = {"abc","aaa034","12a12"};
    char **p = str;

    // 打印字符串
    // for (int i = 0; i < 3; i++)
    // {
    // printf("%s\\n", *p);
    // p++;
    // }

    // 打印字符
    int i = 0;
    while(**p != '\\0')
    {
    printf("%-2c",**p);
    (*p)++;
    }
    printf("\\n");
    return 0;
    }

    ② 与二维数组的差异 二维数组名是数组指针类型,直接赋值给二级指针会导致类型不匹配

    // 数组指针可以指向一个二维数组
    int arr[2][3] = {{1,3,5},{11,33,55}};
    int (*p)[3] = arr;

    // 二级指针不等效二维数组
    int **k = arr; // 编译报错 arr类型 int(*)[3] 不兼容 k类型 int**

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » C语言:指针
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!