指针数组以及利用函数指针来实现简易计算器及typedef关键字(指针终篇)

本文主要是介绍指针数组以及利用函数指针来实现简易计算器及typedef关键字(指针终篇),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

请添加图片描述

文章目录

  • 🚀前言
  • 🚀两段有趣的代码
    • ✈️typedef关键字
  • 🚀指针数组
  • 🚀简易计算器的实现

🚀前言

基于阿辉前两篇博客指针的基础篇和进阶篇对于指针的了解,那么今天阿辉将为大家介绍C语言的指针剩下的部分,包括指针数组以及利用函数指针来实现简易计算器及typedef关键字,关注阿辉不迷路哦 😘 ,内容干货满满😋,接下来就跟着阿辉一起学习吧👊

🚀两段有趣的代码

以下两段代码出自于《C陷阱和缺陷》这本书,这两段代码有一定的难度,需要有一定的指针基础否则可能看不懂,看不懂的可以翻看阿辉前两篇关于指针的博客。
代码1

( *( void ( * )())0 )()

这段代码确实变态,铁子们别急,让我们分析一下:
1.首先,代码( *( void ( * )())0 )()右边单独的括号()很明显它是函数调用操作符,说明( *( void ( * )())0 )这一大坨代表一个函数名
2.然后,void ( * )()这一坨,铁子们这玩意不就是函数指针类型嘛,被指向函数返回类型是void没有参数, void ( * )()这玩意外面套个括号不就是(类型)强制类型转换嘛

那这不就简单了,不就是把数字0强制转化成一个函数指针,然后解引用调用该函数

代码2

void (*signal(int , void(*)(int)))(int);

void (*signal(int , void(*)(int)))(int)这一坨我们咋一看很懵,不过我要是把这个signal(int , void(*)(int))拎出来铁子们肯定熟,这玩意怎么这么像函数声明,铁子们大胆点,你们看看void (*)(int)这一部分不就是函数指针类型吗,这俩一结合不就是函数声明嘛

signal是函数名,它的两个参数类一个是int,一个是返回值为void参数为int的函数指针类型,然后signal的返回类型也是一个返回值为void参数为int的函数指针类型

这里你可能会想这段码难写可读性还差,其实有解决方法,铁子们咱继续👇

✈️typedef关键字

通过typedef,可以为已有的数据类型定义一个新的名字,使得代码更易读、更易维护
语法格式为:

typedef 类型名 新类型名

例子:

 typedef unsigned int size_t;size_t a;对于size_t创建的变量a其实就是unsigned int类型的

对于指针类型,新类型名必须在*右边
例子:

 typedef int(*parr_t)[5];typedef void(*pfun_t)(int);void (*signal(int , void(*)(int)))(int);对于上面这段函数我们就可以这么写了pfun_t signal(int , pfun_t);可读性直接提升一大截

🚀指针数组

铁子们都知道,数组是自定义类型,前面咱们学了指针的一系列类型,这不咱们数组又添一个大家族——指针数组,指针数组顾名思义是存放指针的数组
指针数组的创建

type* name[const];
name是数组名
const是常量给定数组大小
type*是数组的类型

注意这里要与数组指针区分开,由于[]的优先级高于*,所以type* name[const]name[]先结合表明name是指针,而数组指针type (*name)[const](*name)确保*name先结合表明name是指针
举个栗子👇

int* a1[10];//存放整型指针的指针数组
char* a2[10];//存放字符指针的指针数组
int(*a3[10])[5];//存放数组指针的数组指针数组
int(*a4[10])(int);//存放函数指针的函数指针数组

指针数组有什么用呢?铁子们不要急我们接着看👇

🚀简易计算器的实现

利用switch来实现简易计算器
简易计算器的实现思路:

  • 内置加减乘除四种运算
  • 打印菜单供用户选择运算方式以及退出计算器
  • 输入待计算的数字
  • 输出计算结果
#include <stdio.h>
void menu()
{打印菜单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 x, y;int input = 1;int ret = 0;do{menu();printf("请选择:");scanf("%d", &input);switch (input)//选择{case 1:printf("输入两个操作数:");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("输入两个操作数:");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("输入两个操作数:");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("输入两个操作数:");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;
}

上面的这段利用switch实现的代码,有大量重复的元素导致代码极为臃肿,而且对于后期代码的维护也是极为不便,这里我们观察发现add,sub,mul,div这四个函数有着同样的参数以及返回类型,这有什么用呢?铁子们我们接着看
我们完全可以,创建一个函数指针数组来存放他们

int (*a[])(int,int) = {add,sub,mul,div};

有了这个函数指针数组,我们只需要输入下标便可以通过a[input](x,y)来调用函数,但是下标并没有与菜单对应起来,很简单仅需要在数组里面添一个NULL就行int (*a[])(int,int) = {NULL,add,sub,mul,div}
在这里插入图片描述
然后一堆的switch case语句简化成:

	if (input == 0){printf("退出计算器\n");}else if (input >= 1 && input <= 4){										printf("请输入两个操作数:");scanf("%d %d", &x, &y);ret = pfArr[input](x, y);         printf("%d\n", ret);}else{printf("选择错误,重新选择\n");}

不得不说设计C语言的人真的是厉害,后面如果要添加其他运算仅仅只用添函数改一下菜单以及把数组名加到数组里面就行了,绝真的绝!!!


到这里,阿辉今天对于C语言中指针部分的分享就结束了,希望这篇博客能让大家有所收获, 如果觉得阿辉写得不错的话,记得给个赞呗,你们的支持是我创作的最大动力🌹

请添加图片描述

这篇关于指针数组以及利用函数指针来实现简易计算器及typedef关键字(指针终篇)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/441205

相关文章

HTML5实现的移动端购物车自动结算功能示例代码

《HTML5实现的移动端购物车自动结算功能示例代码》本文介绍HTML5实现移动端购物车自动结算,通过WebStorage、事件监听、DOM操作等技术,确保实时更新与数据同步,优化性能及无障碍性,提升用... 目录1. 移动端购物车自动结算概述2. 数据存储与状态保存机制2.1 浏览器端的数据存储方式2.1.

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

SpringBoot中使用Flux实现流式返回的方法小结

《SpringBoot中使用Flux实现流式返回的方法小结》文章介绍流式返回(StreamingResponse)在SpringBoot中通过Flux实现,优势包括提升用户体验、降低内存消耗、支持长连... 目录背景流式返回的核心概念与优势1. 提升用户体验2. 降低内存消耗3. 支持长连接与实时通信在Sp

Conda虚拟环境的复制和迁移的四种方法实现

《Conda虚拟环境的复制和迁移的四种方法实现》本文主要介绍了Conda虚拟环境的复制和迁移的四种方法实现,包括requirements.txt,environment.yml,conda-pack,... 目录在本机复制Conda虚拟环境相同操作系统之间复制环境方法一:requirements.txt方法

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3