C语言指针详解(3)

前言:

强化数组指针的理解:

        在C语言指针详解(2)-CSDN博客中我们模拟实现了一个二维数组,可能大家对其中的原理还有些模糊,这一章开始之前先梳理一遍。

一维数组的模拟实现:

        再剖析二维数组之前,先来看看一维数组的模拟实现。

int main()
{int arr[] = {1,2,3,4,5,6,7,8,9};int(*a)[9] = &arr;int i = 0;for (i = 0; i < 9; i++){printf("%d ", (*a)[i]);}return 0;
}

   通过画图理解:

           这里解引用a就可以找到数组的首元素。

二维数组的模拟实现:

void Print_arr2(int (*arr2)[4],int a,int b)
{int i = 0;for (i = 0; i < a; i++){int j = 0;for (j = 0; j < b; j++){printf("%d", arr2[i][j]);}printf("\n");}
}
int main()
{int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };//可以看作是一维数组的数组Print_arr2(arr, 3, 4);//这里传进去arr,相当于传进去的是arr首元素的地址,但是arr是一个二维数组,传进去的是第组一维数组}

当然也可以这样打印我的二维数组:

void Print_arr2(int (*arr2)[4],int a,int b)
{int i = 0;for (i = 0; i < a; i++){int j = 0;for (j = 0; j < b; j++){printf("%d", (*(arr2+i))[j]);//这里做了改动,如果大家理解这里的话也可以,原理和一维数组的打印类似}printf("\n");}
}
int main()
{int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };//可以看作是一维数组的数组Print_arr2(arr, 3, 4);//这里传进去arr,相当于传进去的是arr首元素的地址,但是arr是一个二维数组,传进去的是第组一维数组}

函数指针:

        这里介绍一下函数指针,函数指针可以指向一个函数,当然函数指针里面存的就是整个函数的地址,例如:

        我想实现两个数相加之后得到的数平方。

        可以这样写:

#include<stdio.h>
int Add(int a,int b)
{int sum = 0;sum = a + b;return sum;
}
int app(int a, int b, int (*c)(int a, int b))
{return (*c)(a, b) * (*c)(a, b);//调用Add函数
}
int main()
{int a = 0;int b = 12;scanf("%d %d", &a, &b);int c = Add(a,b);printf("%d\n", c);int an = 0;an =  app(a, b, Add);//由于我要使用Add函数求和可以把Add函数传进去printf("%d\n", an);return 0;}

这里的 int (*c)(int a,int b)就是函数指针。

 解读函数指针int (*c)(int a,int b)

        int 表示函数的返回 类型,*表示是指针,c表示这个指针的变量名,后面的()里面的的是函数的形参。

               函数的地址这里有两种表示方式:

        1、&Add

        2、Add

        我们可以取出函数的地址放进函数指针中。然后需要的时候直接用函数指针找到函数然后调用。

函数指针数组:

        刚刚讲完函数指针后,我们可以把好多个函数指针放在数组中,就有了函数指针数组,里面存的是每个函数的地址。

        当需要时候可以取出,(*arr[0])(int ,int )

        例如:

        

int main()
{int a = 0;int b = 0;Add(a,b);Mul(a,b);Div(a, b);Sub(a, b);int (*arr[4])(int ,int ) = {Add,Mul,Div,Sub};//函数指针数组里面存放着函数地址
}

   

    函数指针数组实例(计算器)

        如下是调用函数可以写出一个计算器。

#include<stdio.h>
void mnue()
{printf("*******************************************\n");printf("********** 1.Add         2.Sub*************\n");printf("********** 3.Mul         4.Div*************\n");printf("********** 0.exit             *************\n");printf("*******************************************\n");
}
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;
}
int Div(int a, int b)
{return a / b;
} 
int main()
{int input = 0;do{mnue();printf("请选择需要的计算器<<");scanf("%d", &input);int a = 0;int b = 0;int c = 0;switch (input){case 1:printf("请输入你要计算的数字:");scanf("%d%d", &a, &b);c = Add(a,b);printf("%d\n", c);break;case 2:printf("请输入你要计算的数字:");scanf("%d%d", &a, &b);c = Sub(a, b);printf("%d\n", c);break;case 3:printf("请输入你要计算的数字:");scanf("%d%d", &a, &b);c = Mul(a, b);printf("%d\n", c);break;case 4:printf("请输入你要计算的数字:");scanf("%d%d", &a, &b);c = Div(a, b);printf("%d\n", c);break;case 0:printf("退出计算器\n");break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}

        这组代码我主要用的是函数的调用,当然如果要把它改成指针取用它该怎么做呢?

我们可以把这些函数的地址放在指针函数数组中!

        函数指针数组模拟实现计算机

#include<stdio.h>
void mnue()
{printf("*******************************************\n");printf("********** 1.Add         2.Sub*************\n");printf("********** 3.Mul         4.Div*************\n");printf("********** 0.exit             *************\n");printf("*******************************************\n");
}
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;
}
int Div(int a, int b)
{return a / b;
}
int main()
{int input = 0;do{mnue();printf("请选择需要的计算器<<");scanf("%d", &input);int a = 0;int b = 0;int c = 0;int (*arr[5])(int, int) = { NULL, Add,Sub,Mul,Div };//转移表,函数指针数组//由于选择的时候从1开始,所以再数组前面加一个空指针,if (input == 0){printf("退出计算机\n");}else if(input<=4&&input>=1){printf("请输入你要计算的数字<<");scanf("%d%d", &a, &b);c = (*arr[input])(a, b);printf("%d\n", c);}else{printf("选择错误,请重新选择\n");}} while (input);return 0;
}

这样就可以利用函数指针数组。

      函数指针数组,也被叫作是转移表!

使用排序函数qsort

        首先再C语言中,库函数中有qsort这样一个函数,这个函数是干什么的呢,通过查看C plusplus可以看到:

        

分析:


        这个函数的返货类型是void,参数有void* base,size_t num,size_t size,int, compar(const void *,const void *)

        base意思是需要排序的数组的第一个元素的地址。

        num,意思是这个数组中有多少个要排序的成员。

        size,意思是每个元素的大小。

        compar,是个函数,是用作比较两个元素的函数,返回类型是int,需要传进去两个元素的地址,而且这个比较函数需要自己写,因为电脑不知道你是怎么比较的,你得写出来。

        第一个类型的值小于第二个返回-1

        第一个类型的值等于第二个返回0

        蒂耶戈类型的值大于第二个返回1

        大于0降序

        小于0升序

        类型基本上都是void,size_t,原因是你要进行排序,但是不清楚你要排序的元素是什么类型的,有可能是int型,有可能是char类型,也有可能是double,float类型,所以这里传进去的时候类型只能写成void类型。

        使用一下qsort函数看看效果:

        我想要降序,也就是指向元素如果比第二个大就往前排。

#include<stdlib.h>
int compar(const void*p1,const void *p2)
{return *(int*)p2 - *(int*)p1;//降序
}
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, 4, compar);int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

   模拟实现qsort函数

           我可以模拟实现qsort函数,我们排序可以用冒泡排序去排序(原函数用的不是冒泡排序)

     写my_qsort函数

                先来熟悉一下冒泡排序:

int main()
{int arr[] = {1,2,3,4,5,6,7,8,9,10};int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (i = 0; i < sz-1; i++){int j = 0;for (j = 0; j < sz - 1 - i; j++){if (arr[j] < arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}return 0;
}

需要遍历sz-1次,每次需要比较sz-1-i次。

        需要注意事项:

         1、写出来的函数因为为参数类型为size_t(无符号整型),返回类型是void,所以在比较的时候,需要注意强转。

        2、我们需要写出COM()函数,保证和原函数的compar()的写法一样,返回类型就是int,返回正数,负数,还有0三种情况。

        3、还需要写出一个交换的函数,也就是当条件满足时,要进行交换。

代码如下:

void my_qsort(void *base,size_t size,size_t num,int (*com)(void *p1,void *p2))
{int i = 0;for (i = 0; i < (int)num-1; i++){int j = 0;for (j = 0; j < (int)num - 1 - i; j++){if (COM((char*)base + j * size, (char*)base + (j + 1)*size) <0){Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}

写 int COM(void *p1,void *p2)判断函数:

        代码如下:

int COM(void *f1,void *f2)
{return *(int*)f1 - *(int*)f2;
}

写void Swap()交换函数:


        注意事项:

       1、 因为不知道传进去的类型是什么,但是我们可以找到索要交换元素的每个元素的首元素,

        2、找到首元素后,我们可以找到一个最小单位,也就是char*类型的只访问1个字节,不论是什么类型,都可以一个字节一个字节交换!

void Swap(char *tuf1,char *tuf2,int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *tuf1;*tuf1 = *tuf2;*tuf2 = tmp;tuf1++;tuf2++;}
}

完整代码:

        

int COM(void *f1,void *f2)
{return *(int*)f1 - *(int*)f2;
}
void Swap(char *tuf1,char *tuf2,int size)
{int i = 0;for (i = 0; i < size; i++){char tmp = *tuf1;*tuf1 = *tuf2;*tuf2 = tmp;tuf1++;tuf2++;}
}
void my_qsort(void *base,size_t size,size_t num,int (*com)(void *p1,void *p2))
{int i = 0;for (i = 0; i < (int)num-1; i++){int j = 0;for (j = 0; j < (int)num - 1 - i; j++){if (COM((char*)base + j * size, (char*)base + (j + 1)*size) <0){Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}
void test1(int * arr,int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);my_qsort(arr, 4, sz, COM);test1(arr, sz);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/16806.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java整合EasyExcel实战——2 导出复杂表头

详情代码 实体类 Data public class ComplexHeadData {ExcelProperty({"主标题", "字符串标题"})private String string;ExcelProperty({"主标题", "日期标题"})private Date date;ExcelProperty({"主标题", "数字标…

AI日报|阿里8亿美元购入月之暗面36%股份,Meta首席杨立昆建议不要研究大模型...

文章推荐 阿里通义降价&#xff0c;百度文心免费&#xff0c;一图对比谁是最具性价比大模型&#xff1f; 阿里投资Kimi AI开发商月之暗面&#xff1a;8亿美元购入约36%股权 阿里巴巴在2024财年向AI初创企业月之暗面投资约8亿美元&#xff0c;购入其约36%股权。 月之暗面成立…

这13个前端库,帮我在工作中赢得了不少摸鱼时间

前言 平时开发的过程中&#xff0c;常常会使用到一些第三方库来提高开发效率&#xff0c;我总结了自己工作这么久以来经常用到的 13 个库&#xff0c;希望对大家有帮助&#xff5e; antd 全称应该是Ant Design&#xff0c;这是一个 React 的组件库&#xff0c;旨在提供一套常…

小小“创新券” 有大担当

科技创新券&#xff0c;就是企业在进行项目研发过程中&#xff0c;政府为企业免费发放给企业的一种“权益凭证”&#xff0c;它可以帮助企业向高校、科研院所、科技服务机构等机构购买服务&#xff0c;将大型设备和其他科技创新资源充分利用起来&#xff0c;并通过产研合作等方…

DAOS: A Scale-Out High Performance Storage Stack for Storage Class Memory——论文泛读

Supercomputing Frontiers 2020 Paper 分布式元数据论文阅读笔记整理 问题 企业、政府和学术界出现的数据密集型应用程序将现有的I/O模型扩展到了极限。现代I/O工作负载的特点是元数据与未对齐和碎片化数据的结合比例越来越高。传统的存储堆栈为这些工作负载提供了较差的性能…

✅什么是最左前缀匹配?为什么要遵守?

在 MySQL 中&#xff0c;最左前缀匹配指的是在查询时利用索引的最左边部分进行匹配。当你执行查询时&#xff0c;如果查询条件涉及到组合索引的前几个列&#xff0c;MySQL 就能够利用该复合索引来进行匹配。 组合索引即由多个字段组成的联合索引&#xff0c;比如 idx_col1_col2…

AIGC 003-Controlnet升级你的SD让图像生成更加可控!

AIGC 003-Controlnet升级你的SD让图像生成更加可控&#xff01; 文章目录 0 论文工作1 论文方法2 效果 0 论文工作 ControlNet 论文 (Adding Conditional Control to Text-to-Image Diffusion Models) 提出了一种名为 ControlNet 的神经网络结构&#xff0c;旨在为大型文本到图…

StackExchange.Redis跑起来,为什么这么溜?

StackExchange.Redis 是一个高性能的 Redis 客户端库&#xff0c;主要用于 .NET 环境下与 Redis 服务器进行通信&#xff0c;大名鼎鼎的stackoverflow 网站就使用它。它使用异步编程模型&#xff0c;能够高效处理大量请求。支持 Redis 的绝大部分功能&#xff0c;包括发布/订阅…

创意学习剪辑利器:一键添加动图水印,轻松提升视频专业度与创意新境界!

在数字化时代&#xff0c;视频已成为我们生活中不可或缺的一部分。无论是学习分享、工作展示还是生活记录&#xff0c;视频都以其直观、生动的形式&#xff0c;赢得了广大用户的喜爱。然而&#xff0c;如何在众多的视频中脱颖而出&#xff0c;展现出自己的专业度和创意&#xf…

[AI OpenAI] OpenAI 安全更新

AI 首尔峰会中分享我们的实践 我们自豪地构建并发布了在能力和安全性方面都处于行业领先地位的模型。 超过一亿用户和数百万开发者依赖于我们安全团队的工作。我们将安全视为我们必须在多个时间范围内投资并取得成功的事项&#xff0c;从使今天的模型与我们未来预期的更具能力…

谷歌浏览器使用vue插件查看表单提交的数据

1.查看组件&#xff1a; 对应代码里主页面引用的组件名&#xff1a; 表单名称&#xff0c;对应组件里form表单名&#xff1a; 左边的层次结构&#xff1a; 右边层次结构&#xff1a;

Excel/WPS《超级处理器》同类项处理,合并同类项与拆分同类项目

在工作中处理表格数据&#xff0c;经常会遇到同类项处理的问题&#xff0c;合并同类项或者拆分同类项&#xff0c;接下来介绍使用超级处理器工具如何完成。 合并同类项 将同一列中的相同内容合并为一个单元格。 1&#xff09;用分隔符号隔开 将AB列表格&#xff0c;合并后为…

Spring中@Component注解

Component注解 在Spring框架中&#xff0c;Component是一个通用的注解&#xff0c;用于标识一个类作为Spring容器管理的组件。当Spring扫描到被Component注解的类时&#xff0c;会自动创建一个该类的实例并将其纳入Spring容器中管理。 使用方式 1、基本用法&#xff1a; Co…

企业微信hook接口协议,ipad协议http,已读消息

已读消息 参数名必选类型说明uuid是String每个实例的唯一标识&#xff0c;根据uuid操作具体企业微信send_userid是long要发送的人idisRoom是bool是否是群消息 请求示例 {"uuid":"1753cdff-0501-42fe-bb5a-2a4b9629f7fb","send_userid":788130255…

Unity学习日志

目录 获取相机可视范围的世界坐标(2D) 视口转世界坐标和屏幕转世界坐标的区别: 屏幕转世界坐标 视口转屏幕坐标 视口转屏幕结合3D数学实现可视范围的怪物生成 transform.up游戏对象的方向问题 其实还有一种不用Translate的写法: 修改 transform.up 的行为和影响 C#抽象…

全国各城市间驾车耗时和距离矩阵数据集(更新至2022年)

数据简介&#xff1a;城市之间距离越远&#xff0c;耗时越长。经济发达地区的交通状况较好。各城市之间的驾车耗时和距离存在差异。有些城市之间的交通非常便捷&#xff0c;而有些城市之间的交通则较为不便。这表明中国的交通网络发展尚不平衡&#xff0c;需进一步优化。特别是…

Excel如何统计非数值内容行数

需要用到sum函数&#xff0c;具体公式如下&#xff1a; SUM(IF(ISNONTEXT(G4:G199),0,1))

Go 语言简介 -- 高效、简洁与现代化编程的完美结合

在现代软件开发领域&#xff0c;选择合适的编程语言对于项目的成功至关重要。Go 语言&#xff08;又称 Golang &#xff09;自 2009 年由Google发布以来&#xff0c;以其简洁的语法、高效的并发模型以及强大的性能&#xff0c;迅速成为开发者们的新宠。Go语言不仅融合了传统编译…

icloud照片怎么恢复到相册?2个方法,轻松解决烦恼

在现代生活中&#xff0c;照片承载着我们的回忆和珍贵的时刻&#xff0c;而iCloud提供了便捷的云存储服务&#xff0c;让用户可以方便地备份和同步手机上的照片、视频等文件。 然而&#xff0c;有时候我们可能会不小心删除了在iCloud上的照片&#xff0c;或者想要将iCloud照片…

使用B2M 算法批量将可执行文件转为灰度图像

参考论文 基于二进制文件的 C 语言编译器特征提取及识别 本实验使用 B2M 算法将可执行文件转为灰度图像&#xff0c;可执行文件转为灰度图的流程如图 4-3 所示。将 可执行文件每 8 位读取为一个无符号的的整型常量&#xff0c;一个可执行文件得到一个一维向量&#xff0c; …