深入理解并打败C语言难关之一————指针(5)(最终篇)

前言:

  仔细一想,小编已经把指针的大部分内容都说了一遍了,小编目前有点灵感枯竭了,今天决定就结束指针这一大山,可能很多小编并没有提到过,如果有些没说的小编会在后续博客进行补充道,不多废话了,下面让我们开启今天的指针之旅吧!


目录:

1.函数指针数组

1.1.函数指针数组是什么

1.2.函数指针数组的应用

2.sizeof操作符和strlen函数的辨析

2.1.sizeof操作符

2.2.strlen函数

2.3.二者的比较

3.本节代码展示


正文:

1.函数指针数组

1.1.函数指针数组是什么

  前面我们已经学习了函数指针,数组指针,指针数组等内容 ,看到这读者朋友已经很疑惑了,居然还有函数指针数组这个东西,同样的,我们类比一下,存放着整型的是整型数组,存放指针的是指针数组,以此类推,存放着函数指针的数组,自然就是函数指针数组了,所以,这个很长的玩意就是一个数组,不过存放的内容是函数指针罢了,我们需要学会其的创建方式,我们先把代码放到下面供读者阅读:

int (*p1[3])   ();

  首先,p1会先和[]进行结合,表示这个是一个数组,它的类型就是int (*) ()函数指针类型,所以它存放的类型是函数指针,其实这个稍微有点小绕,所以小编决定同样也用图文的方式来给读者朋友们进行更好的解释:

  为了让各位区分一些指针的名称,小编下面整理了前几篇博客写过的一些指针或者数组来让大家区分:

1.指针数组:

int *p1[3];  //中括号里面的个数看题目,这里为了好看统一用3

2.数组指针(和1进行区分):


int (*p2)[3];

3.函数指针:

int (*p3)( )

4.函数指针数组:

int (*p4[])()  //这个对比下来应该是最复杂的了纯纯

  以上便是小编所说过的一些名称,这些要记住,其中前三个都分别放在了小编写过的(3)和(4)里面,感兴趣的读者朋友可以去看看(下面放上了想关链接):深入理解并打败C语言难关之一————指针(3)-CSDN博客 深入理解并打败C语言难关之一————指针(4)-CSDN博客

  既然我们已经讲完了函数指针数组如何进行创建,那么我们下面就要进行应用了,对于其的应用我们用简易计算机为例子,下面让我们进入下一环节,应用! 

1.2.函数指针数组的应用  

  我相信各位学过了前面的知识,已经会使用了函数和一些重要的语句,那么我们可以通过用这些知识来制作一个简易的计算机(仅仅针对整型),下面我们先来一个不用函数指针数组的简易计算机:

  计算机小编相信读者朋友们都用过,里面的功能有很多,下面我们就以正常算法的加减乘除为例子来进行代码的写,首先我们要先有着菜单页,这个可以模仿小编之前写过的扫雷游戏的菜单页,下面直接代码展示:

void menu()
{printf("***********简易计算机************\n");printf("*****1.加法***********2.减法*****\n");printf("*****3.除法***********4.乘法*****\n");printf("*****0.退出**********************\n");printf("**********************************\n");printf("*********************************\n");
}

  做完菜单后,之后我们就要进入选择环节了,这部分内容其实和扫雷很像,但为了考虑部分读者朋友没有看过那篇文章,小编再来说一下,首先我们可以选用do while语句来一直循环,因为这个语句总会先循环一次在判定条件,之后我们再用switch语句来判定想选哪个选项,之后我们在每次的条件下开始输入我们想要的数,然后进行函数的传参,下面是代码展示:

int main()
{menu();             //对于菜单函数的引用int i = 0;             //这一个是负责选哪一个运算方式的int a = 0;               //这一个和下面那个都是要进行运算的数int b = 0;do                    //进入do while 循环(先循环一次然后看循环条件){printf("请选择你想要的算法:");                //这个是让你选算法的scanf("%d", &i);                      //这个是要输入的字符switch (i)                    //这一些跟菜单上数字对应的方式一一对应{case 0 :                      printf("好的下次光临\n");break;case 1 :printf("请选择您要的操作数:");scanf("%d %d", &a, &b);int c = Add(a, b);printf("%d\n", c);break;case 2 :printf("请选择您要的操作数:");scanf("%d %d", &a, &b);int d = div(a, b);printf("%d\n", d);break;case 3 :printf("请选择您要的操作数:");scanf("%d %d", &a, &b);int f = mul(a, b);printf("%d\n", f);break;case 4 :printf("请选择您要的操作数:");scanf("%d %d", &a, &b);int h = mul(a, b);printf("%d\n", h);break;default :printf("您选错了请重新选择:");break;}} while (i);return 0;
}

  然后我们就要撰写函数部分了,这部分的内容其实很简单,就是对照着自己想要的算法传参就好了,下面直接展现代码:

int Add(int x, int y)
{return x + y;
}
int sub(int x, int y)
{return x - y;
}
int div(int x, int y)
{return x / y;
}
int mul(int x, int y)
{return x * y;
}

   之后我们就写完了这个代码,其实乍一看,这么写是很正常的,但是如果仔细一看,发现其实这个代码是很复杂的,首先它的代码量是很复杂的,这个是可以很快看出来的,并且这个代码感觉有的部分显得很赘余,就比如每次输两个数,光这个操作就已经浪费了很多行了,所以我们可以试想一下,可不可以通过一个总函数,这个函数就已经负责了两个数的输入已经算法的选择,每次我们直接通过调用这个函数就好了,所以我们通过调用函数指针的方式就可以做到对这个代码的优化,下面是这个代码的第一次优化:

void oay(int(*p)(int x, int y))        //这里是通过在函数里面调用函数来实现
{        //此时上面这个函数里面放置着被调用的算法,可以看作函数指针的一个应用int a = 0;int b = 0;printf("请选择您想要运算的两个数:");scanf("%d %d",&a ,&b );int len = (*p)(a, b);printf("%d\n", len);
}

  此时已经让这个代码做到第一次优化了,此时这个优化做到了对于每次选择一个算法都要写一遍scanf的不足,这里其实后者函数是由名字的,这个可以叫做回调函数!不过,此时这个算法其实还有可以提升的空间的,就比如,我们可以利用我们刚学的函数指针数组的内容,咱们把每个算法函数的指针放到函数指针数组里面吗,然后通过输入算法来调用数组中的元素从而调用想要的算法,此时我们仅仅需要用到if语句判断我们所选择的算法是否是我们数组内部就好,废话不多说,下面是代码展示:

int main()
{menu();int i = 0;int a = 0;int b = 0;int(*p[5]) (a,b) = {0,add,sub,div,mul};      //md函数指针数组的名字别写错了do{printf("请选择您想要的算法:");scanf("%d", &i);if (i <= 4 && i >= 1){printf("请输入您想要的数字:");scanf("%d %d", &a, &b);int len = (*p[i])(a, b);         //这相对于函数指针数组的数进行引用了,printf("%d\n", len);}else if (i == 0){printf("期待您的下次游玩");break;}else{printf("您输错了请重新输入:");}} while (i);
}

  这个就是这个代码最主要的优化,可能很多人看了都会是下面这个表情:

   所以算法是有千万种的,一个题目往往可以有很多的算法,各位读者朋友们一定要学会举一反三,这对于后面编程的学习有很大的帮助,另外其实最后一个代码还是有个好名字的,它叫做转移表!下面不多废话,进入本节的一个小重点,sizeof操作符与strlen函数的辨析!

 

2.sizeof操作符和strlen函数的辨析

2.1.sizeof操作符

  这个操作符小编在前面说过,这个是计算数组长度的运算符,不过sizeof和数组(这里用arr)有个特殊的关系,小编在之前的文章说过,sizeof(arr)运算的是数组整个的长度,这个特例大家一定要记住,以后在小编在出辨析题的时候可能会有坑哦~

2.2strlen函数

  这个函数小编在之前也说过,这个函数的作用是计算字符串中\0之前的字符个数的,这里应该暂时没有特殊情况,下面我们进入sizeof操作符和strlen的比较环节,对了,这里放一张strlen库函数的相关图让读者阅读:

2.3.二者的比较

  其实二者本质就有很大的区别,前者是一个操作符,后者是一个库函数,需要包含在头文件<string.h>;前者是计算操作符所占内存的大小,单位是字节,后者是计算字符串中字符的个数;前者并不关注存的数据,给它数据它就闷头计算,后者如果一直找不到\0,如果找不到的话会一直找,可能出现越界现象!所以说二者是有着明显的区别的,读者朋友们一定要好好的区分!下面就放上面计算机的代码:

 

3.本节代码展示:

1.优化前的简易计算机代码:

void menu()
{printf("******************************\n");printf("***********简易计算器*********\n");printf("*******1.加法*****************\n");printf("*******2.减法*****************\n");printf("*******3.除法*****************\n");printf("*******4.乘法*****************\n");printf("*******0.退出*****************\n");
}
int Add(int x, int y)
{return x + y;
}
int sub(int x, int y)
{return x - y;
}
int div(int x, int y)
{return x / y;
}
int mul(int x, int y)
{return x * y;
}
int main()
{menu();             int i = 0;             int a = 0;               int b = 0;do                   {printf("请选择你想要的算法:");               scanf("%d", &i);                      switch (i)                  {case 0 :                      printf("好的下次光临\n");break;case 1 :printf("请选择您要的操作数:");scanf("%d %d", &a, &b);int c = Add(a, b);printf("%d\n", c);break;case 2 :printf("请选择您要的操作数:");scanf("%d %d", &a, &b);int d = div(a, b);printf("%d\n", d);break;case 3 :printf("请选择您要的操作数:");scanf("%d %d", &a, &b);int f = mul(a, b);printf("%d\n", f);break;case 4 :printf("请选择您要的操作数:");scanf("%d %d", &a, &b);int h = mul(a, b);printf("%d\n", h);break;default :printf("您选错了请重新选择:");break;}} while (i);return 0;
}

2.第一次优化后的代码(回调函数)

void menu()
{printf("******************************\n");printf("***********简易计算器*********\n");printf("*******1.加法*****************\n");printf("*******2.减法*****************\n");printf("*******3.除法*****************\n");printf("*******4.乘法*****************\n");printf("*******0.退出*****************\n");
}
int Add(int x, int y)
{return x + y;
}
int sub(int x, int y)
{return x - y;
}
int div(int x, int y)
{return x / y;
}
int mul(int x, int y)
{return x * y;
}
void oay(int(*p)(int x, int y))        
{int a = 0;int b = 0;printf("请选择您想要运算的两个数:");scanf("%d %d",&a ,&b );int len = (*p)(a, b);printf("%d\n", len);
}
int main()
{menu();int i = 0;do{printf("请选择您想要的算法:");scanf("%d", &i);switch (i){case 1:oay(Add);       break;case 2:oay(sub);     break;case 3:oay(div);break;case 4:oay(mul);break;case 0:printf("期待您的下次使用");break;default:printf("您填错数了,请重新填写");break;}} while (i);return 0;
}

3.转移表:

void menu()
{printf("******************************\n");printf("***********简易计算器*********\n");printf("*******1.加法*****************\n");printf("*******2.减法*****************\n");printf("*******3.除法*****************\n");printf("*******4.乘法*****************\n");printf("*******0.退出*****************\n");
}
int Add(int x, int y)
{return x + y;
}
int sub(int x, int y)
{return x - y;
}
int div(int x, int y)
{return x / y;
}
int mul(int x, int y)
{return x * y;
}
int main()
{menu();int i = 0;int a = 0;int b = 0;int(*p[5]) (a,b) = {0,add,sub,div,mul};     do{printf("请选择您想要的算法:");scanf("%d", &i);if (i <= 4 && i >= 1){printf("请输入您想要的数字:");scanf("%d %d", &a, &b);int len = (*p[i])(a, b);        7printf("%d\n", len);}else if (i == 0){printf("期待您的下次游玩");break;}else{printf("您输错了请重新输入:");}} while (i);
}

总结:

  今天小编也是写完了指针这部分的内容,也是终于结束了这部分的书写,说实在越到后期我感觉我掌握的知识越不牢固,就比如上面的函数指针数组,我其实已经忘记这个怎么定义了,这个也是边看以前写的代码边写博客才回忆到的,这里就展现了温故而知新的重要性,所以读者朋友们平时一定要多回顾自己以前学的内容,无论是编程还是别的,不然很容易遗忘的,这里小编就不多废话了,预告一下,下一篇小编就要写小编在学习C语言的时候恩师讲过的一些笔试题,我忘记了不少,所以决定写博客回顾一下,如果文章有错误,请在评论区指出,小编一定会汲取错误,那么,我们下一篇见喽!(ps:下一篇可能晚点发布)

 

 

 

   

  

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

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

相关文章

服务器数据恢复—NTFS文件系统下双循环riad5数据恢复案例

服务器存储数据恢复环境&#xff1a; EMC CX4-480存储&#xff0c;该存储中有10块硬盘&#xff0c;其中有3块磁盘为掉线磁盘&#xff0c;另外7块磁盘组成一组RAID5磁盘阵列。运维人员在处理掉线磁盘时只添加新的硬盘做rebuild&#xff0c;并没有将掉线的硬盘拔掉&#xff0c;所…

ARCGIS 如何对河流等线条图形进行Smooth处理——具有多个断点高阶版

1.线转点折点&#xff08;注意&#xff01;很重要&#xff0c;不是线转点&#xff09; 2.点转线步骤 ## 3 线的融合 2.1 新建Filed 》短精度类型》利用选择工具的 线文件。全选同一条河流点&#xff0c;进入Tabel的选择界面。给同一条河赋值同一个值。 大功告成&#xff01;…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《计及多类型储能调频容量动态申报的电能量与调频市场联合出清方法研究》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

深入探究RTOS的任务调度

阅读引言&#xff1a; 此文将会从一个工程文件&#xff0c; 一步一步的分析RTOS的任务调度实现&#xff0c; 这里选用FreeRTOS分析&#xff0c; 别的也差不多的&#xff0c; 可能在细节上有少许不一样。 目录 1&#xff0c; 常见嵌入式实时操作系统 2&#xff0c; 任务调度的…

【机器学习】第11章 神经网络与深度学习(重中之重)

一、概念 1.神经元模型 &#xff08;1&#xff09;神经网络的基本组成单位 &#xff08;2&#xff09;生物上&#xff0c;每个神经元通过树突接受来自其他被激活神经元的信息&#xff0c;通过轴突释放出来的化学递质改变当前神经元内的电位。当神经元内的电位累计到一个水平时…

Kubernetes Dashboard

Dashboard Dashboard 的项目网站&#xff0c;可以查看说明文档和基本的使用情况。 下载yaml wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.6.0/aio/deploy/recommended.yaml注意需要修改镜像&#xff0c;不然可能会拉去不下来镜像 cat recommended.yaml…

人工智能--自然语言处理NLP概述

欢迎来到 Papicatch的博客 目录 &#x1f349;引言 &#x1f348;基本概念 &#x1f348;核心技术 &#x1f348;常用模型和方法 &#x1f348;应用领域 &#x1f348;挑战和未来发展 &#x1f349;案例分析 &#x1f348;机器翻译中的BERT模型 &#x1f348;情感分析在…

函数(下) C语言

函数下 嵌套调用和链式访问1. 嵌套调用2. 链式访问 函数的声明和定义1. 单个文件2. 多个文件3. static 和 extern3.1 static 嵌套调用和链式访问 1. 嵌套调用 嵌套调用就是函数之间的互相调用&#xff0c;每个函数就像⼀个乐高零件&#xff0c;正是因为多个乐高的零件互相无缝…

Nginx缓存之代理缓存配置

Nginx 的缓存功能是集成在代理模块中的&#xff0c;当启用缓存功能时&#xff0c;Nginx 将请求返回的响应数据持久化在服务器磁盘中&#xff0c;响应数据缓存的相关元数据、有效期及缓存内容等信息将被存储在定义的共享内存中。当收到客户端请求时&#xff0c;Nginx 会在共享内…

当同时绑定mousedown和mouseup时,不执行mouseup

问题描述&#xff1a; 当我同时给一个标签添加mousedown和mouseup两个鼠标事件&#xff0c;点击span的时候会触发mousedown事件&#xff0c;但是不会执行mouseup事件&#xff1b;但是注释图二中的setCloudControl方法又能触发mouseup。 后来查阅资料&#xff0c;发现是在封装a…

[算法刷题积累] 两数之和以及进阶引用

两数之和很经典&#xff0c;通常对于首先想到的就是暴力的求解&#xff0c;当然这没有问题&#xff0c;但是我们如果想要追求更优秀算法&#xff0c;就需要去实现更加简便的复杂度。 这里就要提到我们的哈希表法: 我们可以使用unordered_map去实现&#xff0c;也可以根据题目&a…

【Gradio】Chatbots 如何用 Gradio 创建聊天机器人

Creating A Chatbot Fast 简介 聊天机器人是大型语言模型的一个流行应用。使用 gradio &#xff0c;您可以轻松构建您的聊天机器人模型的演示&#xff0c;并与您的用户分享&#xff0c;或者使用直观的聊天机器人用户界面自己尝试。 本教程使用 gr.ChatInterface() &#xff0c;…

SpringMVC系列四: Rest-优雅的url请求风格

Rest请求 &#x1f49e;Rest基本介绍&#x1f49e;Rest风格的url-完成增删改查需求说明代码实现HiddenHttpMethodFilter机制注意事项和细节 &#x1f49e;课后作业 上一讲, 我们学习的是SpringMVC系列三: Postman(接口测试工具) 现在打开springmvc项目 &#x1f49e;Rest基本介…

基于Spark3.3.4版本,实现Standalone 模式高可用集群部署

目录 一、环境描述 二、部署Spark 节点 2.1 下载资源包 2.2 解压 2.3 配置 2.3.1 配置环境变量 2.3.2 修改workers配置文件 2.3.3 修改spark.env.sh文件 2.3.4 修改spark-defaults.conf 2.4 分发 2.5 启动服务 2.5.1 启动zookeeper 2.5.2 启动hdfs 2.5.3 启动spar…

归并排序 (递归实+非递归)

前言 归并排序是一种逻辑很简单&#xff0c;但是实现有点难度的排序&#xff0c;尤其是非递归&#xff0c;对于区间的把握更是需要一点逻辑的推导&#xff0c;但是没有关系&#xff0c;轻松拿捏 归并排序gif 归并排序单趟实现 1&#xff0c;创建tmp数组&#xff0c; 2&#xff…

javaWeb项目-在线考试系统详细功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、Java简介 Java语…

「Qt Widget中文示例指南」如何实现一个滑动条(一)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 滑动条示例展示了如…

轻轻松松上手的LangChain学习说明书

本文为笔者学习LangChain时对官方文档以及一系列资料进行一些总结&#xff5e;覆盖对Langchain的核心六大模块的理解与核心使用方法&#xff0c;全文篇幅较长&#xff0c;共计50000字&#xff0c;可先码住辅助用于学习Langchain。 一、Langchain是什么&#xff1f; 如今各类AI…

昇思25天学习打卡营第1天|快速入门

学AI还能赢奖品&#xff1f;每天30分钟&#xff0c;25天打通AI任督二脉 (qq.com) 本节通过MindSpore的API来快速实现一个简单的深度学习模型。若想要深入了解MindSpore的使用方法&#xff0c;请参阅各节最后提供的参考链接。 import mindspore from mindspore import nn from …

项目训练营第一天

项目训练营第一天 springboot后端环境搭建 1、首先需要找文章下载好tomcat、JDK、maven、mysql、IDEA。&#xff08;软件下载及环境变量配置略&#xff09; 2、在下载好的IDEA中&#xff0c;选择新建spring initial项目&#xff0c;选定java web&#xff0c;即可新建一个spri…