指针数组以及利用函数指针来实现简易计算器及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

相关文章

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义