C语言-------指针进阶(2)

news2024/12/19 12:34:58

1.指针数组

指针数组表较简单,类比整型数组,字符数组,整型数组里面的元素都是整型变量,字符数组里面

的元素是字符类型,那么指针数组就是数组里面的每个元素都是指针类型,例如int*arr[5]就是一个

指针数组,数组里面的元素都是int*的指针类型;

2.数组指针

数组指针是什么,如何使用,我们回忆一下二维数组传参,我们知道一维数组的传参,例test函数

test(arr)参数arr是数组名,就是数组首个元素的地址,我们也可以使用数组接受,也可以使用指针

指向首个元素的地址,通过指针的移动打印数组的元素;

同理,二维数组传参,例如arr[3][5],传递参数test(arr),arr是二维数组的名字,但是不是设个元素的

地址,而是首行元素的地址,这个时候如果想要使用指针接受,这个指针就应该是数组指针,指向

的是一个数组,还是拿这个3行5列数组举例,对于二维数组我们可以这样理解,把二维数组理解成

3个一维数组,实际上传递进去的是第一行以为数组的地址,有5个元素,我们使用数组指针

int(*p)[5]进行接收,这个数组指针表示指向5个元素,每个元素的类型是int类型,数组指针的名字

是p指针,指针类型int(*)[5],指针的类型决定了对指针进行加一操作会跳过几个字节,如果是普通的

整形指针数组,加一就跳过4个字节,但是这里的p指针的类型是int(*)p,所以加一会跳过5个元素,

也就是20字节。

3.函数指针变量

我们知道数组名表示 数组首个元素的地址,函数名同样表示函数的地址,取地址数组名表示整个

数组的地址,但是取地址函数名仍然是函数的地址,和直接的函数名没有区别

图片里面int (*p)(int,int)就是定义函数指针,这个函数指针的参数有2个,都是int类型

这个函数的返回类型是int类型,实际上在进行调用的时候,加上星号只是为了表示他是函数指针

加上2个或者多个星号都不影响使用,不加星号都是可以的,通过打印结果也可以知道,

看似,即使没有函数指针,我们也可以对函数进行使用,实际上后续函数指针会发挥巨大作用

4.二段有趣的代码分析

1 (*(void (*)())0)();

这个里面的void(*)()是函数指针类型,放在括号里面就是进行强制类型转换,把0转换成函数指针类

型,0是个地址,这里的星号同上,是可以省略的,调用0地址处的这个函数,(这里面的0仅仅是一

个地址)这个函数指针没有参数,传递的参数也是空的,如果要调用100地址处的函数,就是

100,总言之,这是一次函数的调用;

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

这个里面的void(*)(int)也是函数指针变量,参数int类型,返回void类型,signal是一个函数,函

数的参数是int类型,和函数指针类型,去掉后是void(*)(int)还是一个函数指针类型,也就是这个函

数的返回值是函数指针类型,函数的声明只需要高数参数的类型,可以不写名字,可能初学者会问

可不可以写为void(*)(int)  signal(int,void(*)(int),或许这样写更加清楚,但是编译器不支持;实质上

这个是函数的声明;

5.typedef关键字的使用

上面的这个例子,对于比较长的数据类型或者指针类型,名字我们可以进行简化,这个时候就有了

typedef关键字

typedef unsigned int  ptr就是把unsigned int这个比较长的类型用ptr代替

我们定义unsigned int a=10;就可以直接写为ptr a=10,使得原来复杂代码简单化,就是重新起名字

还例如指针类型也可以进行简化,int*类型也可以这样简化,typedef int* asd,就是简化后名字asd

int(*p)[5]是数组指针,类型int(*)[5],也可以重新命名,不是int(*)[5] ptr,需要写为typedef int(*ptr)[5]

ptr也是一种类型了,平时的int(*p2)[5]=&arr(这里的p2就是指针变量)就可以写为ptr p2=&arr,

函数指针类型重命名,原来的 void (*pf)(int)函数指针,typedef  void(*)(int)  ptr;以后定义就可以

写作ptr p2=&add,这样定义函数指针类型;

同样使用ptr重命名函数指针,void (*signal(int , void(*)(int)))(int);就可以简化为

ptr signal(int,ptr),变得更加简单,简洁高效。

typrdef  int* ptr;就是关键字重命名;

#define int* PTR就是遇到PTR使用int*替代,ptr a相当于int*a,这样也可以简化;

第一一个变量的时候两者无区别,定义2个时候就有区别

ptr  a,b;可以同时定义a,b都是int*类型

PTR a,b;不能同时定义a,b是int*类型,只能定义a ,b还是默认的int 类型;

由此可见,使用重命名的时候,尽量使用typedef,使用#define可能会出现问题。

6,函数指针数组

(1)首先讲一下函数指针数组如何使用:

每一个运算的法则都是函数指针,因为他们的参数,返回类型都是相同的,所以我们可以放到

一个数组里面,这个数组就叫做函数指针数组,循环里面直接调用就可以了;

函数指针数组就是在函数指针名字后面加上元素个数;

(2)接下来讲一下函数指针数组如何使用:以一个计算机的构建为例,这个计算机可以实现

简单的四则运算;下面是自定义函数和主函数的代码

下面的是函数

int 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 divi(int x, int y)
{
	return x / y;
}

下面主函数(注意除法的自定义函数不能直接使用div,本人亲测,div和库函数里面的div冲突)

void menu()
{
	printf("*****************************************\n");
	printf("**********1.add**************************\n");
	printf("**********2.sub**************************\n");
	printf("**********3.mul**************************\n");
	printf("**********4.divi**************************\n");
	printf("**********0.exit*************************\n");
}
int main()
{
	int input = 0;
	int x = 0;
	int y = 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("%d\n", ret);
			break;
		case 2:
			printf("请输入2个数字\n");
			scanf("%d %d", &x, &y);
		    ret = sub(x, y);
			printf("%d\n", ret);
			break;
		case 3:
			printf("请输入2个数字\n");
			scanf("%d %d", &x, &y);
			ret = mul(x, y);
			printf("%d\n", ret);
			break;
		case 4:
			printf("请输入2个数字\n");
			scanf("%d %d", &x, &y);
			ret = divi(x, y);
			printf("%d\n", ret);
			break;
		case 0:
			printf("退出计算器");
			break;
		default:
			printf("请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

思考分析简化:

 这个是一个普通的计算器,只有加减乘除法则运算;

这样看来,每个case都要重复,显示的有些冗余,这个时候可以使用函数指针数组;

int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	int(*ptr[5])(int,int) = {NULL,add,sub,mul,divi};
	do
	{
		menu();
		printf("请选择\n");
		scanf("%d", &input);
		if (input >= 1 && input <= 4)
		{
			printf("请输入2个数字\n");
			scanf("%d %d", &x, &y);
			ret = ptr[input](x, y);
			printf("%d\n", ret);
		}
		else if (input == 0)
		{
			printf("退出计算器\n");
			break;
		}
		else
		{
			printf("选择错误,重新选择\n");
		}
	} while (input);
	return 0;
}

这个时候,引入数组,里面就是函数,因为要使我们输入的input和数组元素的下标相对应,

所以我们把第一个元素设置为NULL,这样我们选择哪个数字,就可以找到对应函数地址,使用这个

函数,这样函数的下标就是1,2,3,4了;ptr[input]直接找到对应的地址,使用这个函数

而且,如果想要增加法则,只需要增加数组元素就可以了,如果不是用这种数组,就需要

增加case语句,里面的内容还是需要重复,更加复杂,函数指针数组的优势就体现了出来。

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

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

相关文章

数字化转型导师坚鹏:金融机构数字化营销方法和案例研究

金融机构数字化营销方法和案例研究 课程背景&#xff1a; 很多金融控股集团存在以下问题&#xff1a; 不清楚金融机构数字化营销方法&#xff1f;&#xff08;以证券、保险、租赁行业为例&#xff09; 不清楚金融机构数字化营销案例&#xff1f;&#xff08;以证券、保险…

成功案例(IF=13.8)| 基因组de novo联合Hi-C组装萝卜高质量基因组

1 研究背景 萝卜&#xff08;Raphanus sativus L.&#xff09;是世界范围内重要的根茎蔬菜作物。肉质主根是最重要的可食器官&#xff0c;提供了许多有益的营养物质&#xff0c;包括碳水化合物、矿物质、核黄素、植物化学物质和膳食纤维。然而&#xff0c;尽管萝卜具有生物学…

24V转3.3V 36V转5V 60V转5V降压芯片 H6246

24V转5V降压芯片的工作原理&#xff1a; 通过控制开关管和脉冲宽度调制&#xff08;PWM&#xff09;技术实现的。当输入电压为24V时&#xff0c;芯片会将其通过开关管进行开关调节&#xff0c;控制电流的流动。同时&#xff0c;芯片还会利用PWM技术&#xff0c;调节开关管的开…

【喜报】蚂蚁科技成功获聘隐私计算联盟副理事长单位!

蚂蚁科技获聘信通院隐私计算联盟副理事长单位 近日&#xff0c;由中国信息通信研究院、中国通信学会、隐私计算联盟等单位联合承办的隐私计算大会上&#xff0c;蚂蚁科技集团股份有限公司获聘2023-2024年度"隐私计算联盟副理事长"单位。 隐私计算联盟是在工业和信息…

Spring初始(相关基础知识和概述)

Spring初始&#xff08;相关基础知识和概述&#xff09; 一、Spring相关基础知识&#xff08;引入Spring&#xff09;1.开闭原则OCP2.依赖倒置原则DIP3.控制反转IoC 二、Spring概述1.Spring 8大模块2.Spring特点2.Spring的常用jar文件 一、Spring相关基础知识&#xff08;引入S…

watchdog---基于python的文件夹监控框架

说明及介绍 watchdog是一个用于监控文件系统变化的Python库&#xff0c;可以监控文件或目录的创建、修改、删除等操作。watchdog可以通过监听文件系统事件来实时监控文件或目录的变化&#xff0c;当文件系统中的文件或目录发生变化时&#xff0c;watchdog会触发相应的事件&…

AFL mmap

fuzz_one函数中看到这么一句话 orig_in in_buf mmap(0, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);对mmap不太理解&#xff0c;不明白这句话的意思。 首先&#xff0c;得去了解下mmap函数是干什么的&#xff0c; 找到一个简单易懂的博客&#xff1a;https://www.j…

RT-DETR算法优化改进: 特征融合涨点篇 | 广义高效层聚合网络(GELAN) | YOLOv9

💡💡💡本文独家改进:即结合用梯度路径规划(CSPNet)和(ELAN)设计了一种广义的高效层聚合网络(GELAN),高效结合RT-DETR,实现涨点。 💡💡💡在多个私有数据集和公开数据集VisDrone2019、PASCAL VOC实现涨点 RT-DETR魔术师专栏介绍: https://blog.csdn.net/…

第15届蓝桥STEMA测评真题剖析-2024年1月28日Scratch编程初中级组

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第173讲。 第15届蓝桥第4次STEMA测评&#xff0c;这是2024年1月28日举办的STEMA&#xff0c;比赛仍然采取线上形式。这…

c++数据结构算法复习基础-- 3 --线性表-单向链表-笔试面试常见问题

1、单链表逆序 思路图 代码实现 //著: 链表结构里记得加 friend void ReverseLink(Clink& link); void ReverseLink(Clink& link) {Node* p link.head_->next_;while( p nullptr){return;}Node* q p->next_;link.head_->next_ nullptr;while(p ! nullpt…

linux常用的解压缩工具介绍

在Linux系统中&#xff0c;解压缩文件是一种常见的操作。有多种工具可以用来解压缩文件&#xff0c;它们各自有不同的特点和优势。以下是一些常用的Linux解压缩工具&#xff0c;以及它们之间的区别。 1. tar tar是一个强大的文件打包和解包工具&#xff0c;它可以用来打…

基于springboot+vue的响应式企业员工绩效考评系统(源码+论文)

文章目录 前言 一、功能设计 1 普通员工功能 2 主管功能 3 系统管理员功能 4 评分标准功能 5 PC端与手机端 6 制图 二、功能实现 普通员工 1普通员工登录 2公告板块 3日志板块 主管 1主管登录 2公告板块 3日志板块 4绩效评分板块 5个人信息板块 系统管理员…

身份证识别系统(安卓)

设计内容与要求&#xff1a; 通过手机摄像头捕获身份证信息&#xff0c;将身份证上的姓名、性别、出生年月、身份证号码保存在数据库中。1&#xff09;所开发Apps软件至少需由3-5个以上功能性界面组成。要求&#xff1a;界面美观整洁、方便应用&#xff1b;可以使用Android原生…

基于springboot+vue的校园爱心捐赠互助管理系统(源码+论文)

目录 前言 一、功能设计 二、功能实现 三、库表设计 四、论文 前言 随着经济水平和生活水平的提高在校大学生在校需要处理的物品也在不断增加&#xff0c;同时校园内还存在很多贫困生&#xff0c;可以通过线上平台实现资源的整合和二次利用&#xff0c;通过线上平台求助信…

c语言内存分配知识,堆,栈,全局静态,常量,代码

c语言中一些内存的作用 参考&#xff1a;https://blog.csdn.net/m0_49768044/article/details/131391832&#xff0c;其他

CSS列表属性

CSS列表属性 列表相关的属性&#xff0c;可以作用在 ul、ol、li 元素上。 代码如下&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>列表相关属性</title><style>ul {/* …

C++:类与对象(3)

创作不易&#xff0c;感谢三连 一、深入解析构造函数 如上图&#xff0c;在一般情况下&#xff0c;我们认为A类中的_a1和_a2只不过是声明&#xff0c;并没有开空间&#xff0c;而真正的空间开辟是在【定义】的时候&#xff0c;也就是我们根据这个类实例化出整个对象的时候。 …

深入分析Android运行时环境ART:原理、特点与优化策略

摘要 随着移动互联网的快速发展&#xff0c;智能手机的性能和功能日益强大&#xff0c;其中Android操作系统因其开放性和灵活性而占据主导地位。Android运行时环境&#xff08;ART&#xff09;作为执行应用程序代码的关键组件&#xff0c;在系统性能和用户体验方面起着至关重要…

【Web安全靶场】xss-labs-master 1-20

xss-labs-master 其他靶场见专栏 文章目录 xss-labs-masterlevel-1level-2level-3level-4level-5level-6level-7level-8level-9level-10level-11level-12level-13level-14level-15level-16level-17level-18level-19level-20 level-1 第一关没有进行任何限制&#xff0c;get请求…

服务器感染了.ma1x0勒索病毒,如何确保数据文件完整恢复?

引言&#xff1a; 网络安全成为至关重要的议题。.ma1x0勒索病毒是当前网络威胁中的一种恶意软件&#xff0c;它的出现给用户带来了极大的困扰。然而&#xff0c;正如任何挑战一样&#xff0c;我们也有方法来面对并克服.ma1x0勒索病毒。本文将全面介绍这种病毒的特点&#xff0…