返回顶部
首页 > 资讯 > 数据库 >【C进阶】指针(二)
  • 774
分享到

【C进阶】指针(二)

c语言算法数据结构 2023-09-12 07:09:03 774人浏览 八月长安
摘要

六、函数指针数组 数组是一个存放相同类型数据的存储空间,我们已经学习了指针数组 eg: int *arr[10]       //整形指针数组-数组-存放的是整形指针 char *arr[5]      //字符指针数组-数组-存放的

六、函数指针数组

数组是一个存放相同类型数据的存储空间,我们已经学习了指针数组

eg:

int *arr[10]       //整形指针数组-数组-存放的是整形指针

char *arr[5]      //字符指针数组-数组-存放的是字符指针

那么把函数的地址存到一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢

int (*parr【10】)( )

parr先和【】结合,说明parr是数组,那么数组的内容是什么呢?

是int(*)()类型的函数指针(从函数指针+数组名【】

总结:

看pa和【】还是和*结合,

如果是和【】结合,那么pa就是数组

如果是和*结合,那么pa就是指针

eg:函数指针数组可以将类型为函数指针的元素放在一起

int Add(int x, int y){return x + y;}int Sub(int x, int y){return x - y;}int main(){int (*pf1)(int, int) = &Add;int (*pf2)(int, int) = ⋐//数组中存放相同类型的多个元素int (*pfArr[2])(int, int) = { &Add,&Sub };//pfArr是函数指针数组-存放函数指针的数组return 0;}

函数指针数组的用途:转移表

eg2:(计算器)

基础版:但是这个代码不好,如果想实现||,&&,&,|,>>,<<更多的功能还得重复写一些步骤,就很冗余

#includeint add(int x, int y){return x + y;}int sub(int x, int y){return x - y;}int mul(int x, int y){return x * y;}int div(int x, int y){return x / y;}void menu(){printf("***********************************\n");printf("***1.add       2.sub***************\n");printf("***3.mul       4.div***************\n");printf("***0.exit *************************\n");printf("***********************************\n");}int main(){int x, y = 0;int input = 0;int ret = 0;do{menu();printf("请选择:\n");scanf("%d", &input);switch (input){case 1:printf("请输入2个操作数:\n");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret=%d\n", ret);break;case 2:printf("请输入2个操作数:\n");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret=%d\n", ret);break;case 3:printf("请输入2个操作数:\n");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret=%d\n", ret);break;case 4:printf("请输入2个操作数:\n");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret=%d\n", ret);break;case 0:printf("退出程序\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;}

使用函数指针数组实现:

这样就统一起来了,更加简洁,方便,如果要加功能,只需要改菜单,数组定义,input的范围

#includeint add(int x, int y){return x + y;}int sub(int x, int y){return x - y;}int mul(int x, int y){return x * y;}int div(int x, int y){return x / y;}void menu(){printf("***********************************\n");printf("***1.add       2.sub***************\n");printf("***3.mul       4.div***************\n");printf("***0.exit *************************\n");printf("***********************************\n");}int main(){int x, y = 0;int input = 1;int ret = 0;int (*p[5])(int, int) = { NULL,&add,&sub,&mul,&div };//转移表(加个NULL是为了和数组下标统一)while (input){menu();printf("请选择:\n");scanf("%d", &input);if (input == 0){printf("退出程序\n");}else if (input <= 4 && input >= 1){printf("请输入2个操作数:\n");scanf("%d %d", &x, &y);ret = (*p[input])(x, y);//*可不写,和函数指针一样printf("ret=%d\n", ret);}else{printf("输入错误,请重新输入\n");}}return 0;}

注意:这样改的条件是:函数的返回类型和参数类型一样


七、指向函数指针数组的指针

(这部分内容不重要,但是可以拓展视野)

类比:指向指针数组的指针  int*(*p)【3】=&arr

指向函数指针数组的指针是一个指针,指针指向一个数组,数组元素都是函数指针

eg:

int(*(*p)【5】)(int,int)=&pfArr   p是指向函数指针数组的指针

int(*     【5】)(int,int)=&pfArr   函数指针数组类型

int(*        )(int,int)=&pfArr         函数指针类型


八、回调函数

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

简单来说就是有两个函数,通过函数指针得到一个函数A(回调函数)的地址, 另一个函数

B(&A)实现间接调用A函数

注意:依赖函数指针才有回调函数

eg1:

计算器基础版简化:

这个部分每个case都在重复,那就用一个函数进行代替:

case 1:printf("请输入2个操作数:\n");scanf("%d %d", &x, &y);ret = add(x, y);//sub/mul/divprintf("ret=%d\n", ret);break;

运用回调函数进行改进:

#includeint add(int x, int y){return x + y;}int sub(int x, int y){return x - y;}int mul(int x, int y){return x * y;}int div(int x, int y){return x / y;}void menu(){printf("***********************************\n");printf("***1.add       2.sub***************\n");printf("***3.mul       4.div***************\n");printf("***0.exit *************************\n");printf("***********************************\n");}void calc(int (*pf)(int,int)){int x, y = 0;printf("请输入2个操作数:\n");scanf("%d %d", &x, &y);int ret = pf(x, y);printf("ret=%d\n", ret);}int main(){int input = 0;do{menu();printf("请选择:\n");scanf("%d", &input);switch (input){case 1:calc(add);break;case 2:calc(sub);break;case 3:calc(mul);break;case 4:calc(div);break;case 0:printf("退出程序\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;}

图解:

借助calc函数回调add,sub,mul,div等函数,是通过函数地址回调函数,逻辑就是进入case语句calc函数开始执行,当执行到ret=pf(x,y),又回调add等函数,回调结束又回到calc函数中

注意:add,sub,mul,div这些函数才是回调函数,而不是calc函数


eg2:qsort快排:

对数据的排序方法有很多:冒泡排序,选择排序,插入排序,快速排序

为了对比qsort函数进行排序我们这里再来复习一下冒泡排序:

#includevoid print_arr(int* arr, int sz){for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");}void bubble_arr(int* arr, int sz){ for (int i = 0; i < sz-1; i++)//趟数{for (int j = 0; j < sz-i-1; j++)//每一趟冒泡排序{if (arr[j] > arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}}int main(){int arr[] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);print_arr(arr, sz);bubble_arr(arr, sz);print_arr(arr, sz);return 0;}

但是这个冒泡排序只能排序int类型的数据,下面就来介绍qsort快排:

qsort函数是一个库函数,底层使用的快速排序的方式,对数据进行排序,这个函数可以直接使用,可以用来排序任意类型的数据

头文件:#include

void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );

qsort(被排序数组的初始位置,要排序的数组的元素个数,一个元素所占字节,比较函数)

重点是最后一个参数,比较函数:

如果要升序(elem1

如果要降序(elem1>elem2),则return>0,就要return elem2-elem1

#include#includeint int_cmp(const void* e1, const void* e2){return (*(int*)e1 - *(int*)e2);}int main(){int arr[] = { 1,3,5,7,9,2,4,6,8,0 };qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), int_cmp);for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", arr[i]);}printf("\n");return 0;}

比较不同类型的数据,方法是有差异的:

(1)排序整形数据,两个整形可以直接直接使用><比较

(2)比较结构体数据,两个结构体的数据可能不能使用>比较

(eg:字符串的比较得用strcmp)

 注意比较函数(__cdecl *compare )的返回值一定为int类型

比较函数就是回调函数,比较时没有直接用比较函数(__cdecl *compare ),而是通过函数指针传给qsort函数

为什么用void*类型的指针 ?

void*指针:无具体类型的指针

不能进行解引用操作,也不能进行+-整数的操作

它是用来存放任意类型数据的地址的

 结构体类型数据快排:

//结构体类型struct Stu{char name[20];int age;};//int cmp_stu_by_age(const void* e1, const void* e2)//{//return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;//}//int cmp_stu_by_name(const void* e1, const void* e2)//{//return *(struct *)e1 - *(int*)e2;//}int cmp_stu_by_name(const void* e1, const void* e2){return strcmp(((struct Stu*)e1)->name , ((struct Stu*)e2)->name);}int main(){struct Stu arr[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 12} };int sz = sizeof(arr) / sizeof(arr[0]);//qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);return 0;}

double类型的数据快排:这两种都可以

//浮点型数据int cmp_double(const void* e1, const void* e2){return (int)(*(double*)e1 > *(double*)e2);}//int cmp_double(const void* e1, const void* e2)//{//return *(double*)e1 < *(double*)e2?-1:1 ;//}

本次内容就到此啦,欢迎评论区或者私信交流,觉得笔者写的还可以,或者自己有些许收获的,麻烦铁汁们动动小手,给俺来个一键三连,万分感谢 ! 

来源地址:https://blog.csdn.net/qq_73017178/article/details/132745589

您可能感兴趣的文档:

--结束END--

本文标题: 【C进阶】指针(二)

本文链接: https://lsjlt.com/news/404128.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 【C进阶】指针(二)
    六、函数指针数组 数组是一个存放相同类型数据的存储空间,我们已经学习了指针数组 eg: int *arr[10]       //整形指针数组-数组-存放的是整形指针 char *arr[5]      //字符指针数组-数组-存放的...
    99+
    2023-09-12
    c语言 算法 数据结构
  • C语言进阶:指针的进阶(1)
    目录指针进阶字符指针字符指针的作用字符指针的特点指针数组指针数组的定义指针数组的使用总结指针进阶 我们在初阶时就已经接触过指针,了解了指针的相关内容,有: 指针定义:指针变量,用于...
    99+
    2024-04-02
  • C语言进阶:指针的进阶(2)
    目录数组指针数组指针的定义&数组名和数组名数组指针的使用反面用例正面用例Example类型辨别方法总结数组指针 由前面的例子,不难得出,数组指针是指向数组的指针,是指针而非...
    99+
    2024-04-02
  • C语言进阶:指针的进阶(3)
    目录数组传参和指针传参一维数组传参二维数组传参一级指针传参二级指针传参总结数组传参和指针传参 实践之中不免会碰到数组和指针作函数参数而如何设计形参的问题。 一维数组传参 一维数...
    99+
    2024-04-02
  • C语言进阶:指针的进阶(4)
    目录函数指针函数指针的定义函数指针的类型函数指针的使用Example总结函数指针 函数指针的定义 整型指针存放整型的地址;数组指针存放数组的地址;那么类比可得,函数指针存放函数的地...
    99+
    2024-04-02
  • C语言进阶:指针的进阶(5)
    目录函数指针数组函数指针数组的定义函数指针数组的使用转移表回调函数指向函数指针数组的指针总结函数指针数组 //整型数组 - 存放整型变量 int arr[10]; //字符数组 ...
    99+
    2024-04-02
  • C语言进阶学习之指针
    目录1.指针概念回顾2.字符指针3.数组指针和指针数组3.1数组指针的含义3.2&数组名vs数组名3.3数组指针4.数组传参和指针传参4.1一维数组传参4.2二维数组传参4....
    99+
    2024-04-02
  • C语言 指针数组进阶详解
    目录指针与数组中的sizeof与strlensizeofstrlen数组名1、一维数组整型数组字符数组指针数组2、二维数组指针笔试题 笔试题1笔试题2笔试题3笔试题4笔试题...
    99+
    2024-04-02
  • 零基础详解C语言指针进阶
    目录前言1.字符指针例题 12.指针数组例题 23.数组指针3.1数组指针的定义3.2 &数组名与数组名3.3 数组指针的使用4.数组与指针在函数里的传参4.1 一维数组的传...
    99+
    2024-04-02
  • 【C进阶】指针和数组笔试题解析
    做题之前我们先来回顾一下 对于数组名的理解:除了以下两种情况,数组名表示的都是数组首元素的地址 (1)sizeof(数组名):这里的数组名表示整个数组 (2)&(数组名) :这里的数组名也表示整个数组 一、一维数组 int a[]...
    99+
    2023-09-26
    c语言 算法 开发语言
  • C++二级指针和指针的引用
    目录1、形参与实参均为指针时达不到此目的2、解决方案——指针引用或二级指针(1)形参为二级指针**p(2)形参为指针引用*&p3、总结 目的:形参指针...
    99+
    2024-04-02
  • C语言中二级指针解析(指向指针的指针)
    目录二级指针(指向指针的指针)二级指针的定义与理解二级指针定义格式二级指针赋值实例二级指针(指向指针的指针) 指针可以指向一份普通类型的数据,例如 int、double、char 等...
    99+
    2024-04-02
  • C语言进阶教程之函数指针详解
    目录一、函数指针1.概念1.2函数指针的使用方法1.3练习巩固1.4小结一下二、阅读两段有趣的代码1.( *(void( *)( ))0 )( )2.void (* signal(i...
    99+
    2024-04-02
  • C语言中的指针 初阶
    目录1.指针是什么2.指针和指针类型3.野指针3.1野指针成因3.2如何规避野指针4.指针的运算4.1指针±整数4.2指针-指针4.3指针的关系运算5.指针和数组6.二级指针7.指针...
    99+
    2024-04-02
  • 【C语言初阶】指针篇—下
    目录 4. 指针运算4.1 指针+-整数4.2 指针-指针4.3 指针的关系运算 5. 指针和数组6. 二级指针7. 指针数组 C语言初阶—指针上 点击跳转 4. 指针运算 指针...
    99+
    2023-09-01
    c语言 算法 开发语言 指针
  • C语言玩转指针之指针的高阶玩法
    目录前言一、字符指针二、指针数组和数组指针1.指针数组2.数组指针2.1.数组指针是什么?2.2.&数组名和数组名的区别2.3.数组指针的使用三、数组参数与指针参数1.一维数...
    99+
    2024-04-02
  • 掌握指针进阶:探索字符指针、数组指针和指针数组的妙用
    💓博客主页:江池俊的博客⏩收录专栏:C语言进阶之路👉专栏推荐:✅C语言初阶之路 ✅数据结构探索💻代码仓库:江池俊的代码仓库​🎪 社区...
    99+
    2023-09-07
    c语言 开发语言 学习 经验分享
  • C++的二级指针和指针怎么引用
    本篇内容主要讲解“C++的二级指针和指针怎么引用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++的二级指针和指针怎么引用”吧!目的:形参指针改变实参指针所指向的对象(即地址)举例:point...
    99+
    2023-06-29
  • 一篇文章带你了解C语言指针进阶
    目录1.字符指针2.指针数组3.数组指针4.函数指针5.数组传参总结1.字符指针 我们已经知道了数组名在大部分时候表示数组的地址,指针本质上也表示一个地址,那么我们能否用指针来创建一...
    99+
    2024-04-02
  • C++学习进阶篇之类大小计算和this指针
    目录一、类大小计算二、this指针总结一、类大小计算 类的大小是只计算它的成员变量或者自定义成员,不会计算它的成员函数大小。 #include<iostream> usi...
    99+
    2023-05-18
    c++类大小计算方式 c++计算类的大小 c++ this指针用法
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作