带你深入了解c语言指针后续

news2024/10/2 12:22:11

在这里插入图片描述

前言

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻推荐专栏: 🍔🍟🌯 c语言进阶
🔑个人信条: 🌵知行合一
🍉本篇简介:>:介绍c语言中有关指针更深层的知识.
金句分享:

✨在该奋斗的岁月里,✨
✨对得起每一寸光阴.✨

目录

  • 前言
  • 一、函数指针
    • 1.1 函数指针的创建
    • 1.2 函数指针应用
  • 二、函数指针数组
  • 三、函数指针数组指针
  • 四、回调函数

一、函数指针

1.1 函数指针的创建

函数指针,顾名思义,就一个指向函数的指针.
那么

整形指针是接收整形的地址;
字符指针是接收字符的地址.
数组指针是接收数组的地址

函数有地址吗?函数名又可以代表什么?
示例:自定义一个加法函数,观察函数的地址

//函数指针
#include <stdio.h>
int add(int a,int b)//自定义一个加法函数
{
	return a + b;
}
int main()
{
	int a = 2, b = 3;
	int c=add(a, b);
	printf("%d\n", c);//确认一下函数是否正确
	printf("%p\n", &add);//取出函数的地址
	printf("%p\n", add);//用数组名打印
	return 0;
}

运行结果:(在不同环境下地址会不一样,这里采用的是vs x86环境)

5
00E61023
00E61023

不难发现,函数名也可以代表函数的地址.
那么函数指针该怎么写呢?

数组指针为例:
数组指针示例:写一个指向 int arr[10] 数组的数组指针;

第一步:
(*p)		//先确定是一个指针
第二步:
(*p)[10]	//确定指向的是一个有10个元素的数组
第三步:
int(*p)[10]	//确定该数组元素为int型
第四步:
int(*p)[10]=&arr;//将数组的地址赋值给数组指针
//或者int(*p)[10]=arr;

示例2:
函数指针:指向int add(int a,int b)

第一步:
(*p)			//先确定是一个指针
第二步:
(*p)(int,int)	//确定指向的函数有两个参数
第三步:
int (*p)(int,int)	//确定该函数的返回类型
第四步:
int (*p)(int,int)=&add;//将函数的地址赋值给函数指针
//等价于:int (*p)(int,int)=add;

1.2 函数指针应用

那么函数指针有什么用吗?
当然是用来调用函数了.
同样以数组指针为例:
🌰使用数组指针访问数组.

int main()
{
	int arr[10] = { 1,2,3,4,5 };
	int(*p)[10] = arr;

	for (int i = 0; i < 5; i++)
	{
		printf("%d ", ( * p)[i]);
	}
	printf("\n");
	return 0;
}

🌰使用函数指针调用函数

#include <stdio.h>
int add(int a,int b)
{
	return a + b;
}
int main()
{
	int a = 2, b = 3;
	int(*p1)(int, int) = &add;
	int(*p2)(int, int) = add;
	int ret1=add(a,b);
	int ret2=(*p1)(a, b);//写法一
	int ret3=p1(a, b);//写法2
	printf("ret1=%d\nret2=%d\nret3=%d",ret1,ret2,ret3);
	return 0;
}

运行结果:都能完成函数的调用

ret1=5
ret2=5
ret3=5

二、函数指针数组

函数指针数组实质用于存放函数指针数组.
数组的成员都是函数指针.
写法:以数组成员都是指向类似int add(int,int)的函数指针为例

1.先写出函数指针
(int) (*p)(int,int)
2.改成数组
(int) (*p[10])(int,int)//函数指针数组

题目:使用c语言制作简单的计算器.
要求,可以进行加减乘除运算.

//简易计算器
#include <stdio.h>
void menu()//菜单
{
	printf("作者:初阶牛\n");
	printf("	欢迎使用计算器:\n");
	printf("+-------------------------------+\n");
	printf("|	1.add		2.sub	|\n");
	printf("|	3.mul		4.div	|\n");
	printf("|		0.退出		|\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=0, y=0;
	int input = 1;
	int ret = 0;
	do
	{
		menu();//打印菜单
		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;
}

对于上面的代码,我们可以使用函数指针来简化.
感受一下函数的指针的魅力吧!

#include <stdio.h>
void menu()
{
	printf("作者:初阶牛\n");
	printf("	欢迎使用计算器:\n");
	printf("+-------------------------------+\n");
	printf("|	1.add		2.sub	|\n");
	printf("|	3.mul		4.div	|\n");
	printf("|		0.退出		|\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 = 0, y = 0;
	int input = 1;
	int ret = 0;
	int(*arr[5])(int, int)={0,add,sub,mul,div};//使用函数指针数组
	do
	{
		menu();
		scanf("%d", &input);
		if (input > 0 && input < 5)
		{
			printf("输入两个操作数:");
			scanf("%d %d", &x, &y);
			ret=arr[input](x,y);//利用数组下标调用相应的函数
			printf("ret = %d\n", ret);
		}
		else if (input == 0)
		{
			printf("退出计算器\n");
			break;
		}
		else
		{
			printf("很遗憾,并没有这个选项:\n");
			break;
		}
	} while (input);
	return 0;
}

三、函数指针数组指针

函数指针数组指针:
指向一个数组.该数组的成员都是函数指针.
写法:

1.先写出函数指针
char* (*p)(const int, double, char*);
2.改成函数指针数组
char* (*pp[3])(const int, double, char*);
3.最后写成函数指针数组指针
	char* (*(*ppp)[3])(const int, double, char*);

可以通过函数指针p调用函数,
也可以通过函数指针数组的元素,pp[0]调用函数.
最后,可以通过(*ppp)找到函数指针数组,(*ppp)[0]调用函数.

示例:

char* test(const int a, double b, char* c)
{
	char* ret = "AAABBBCCCDDD\n";
	return ret;
}
#include <stdio.h>
int main()
{
	//函数指针
	char* (*p)(const int, double, char*)=test;
	//函数指针数组
	char* (*pp[3])(const int, double, char*);
	pp[0] = test;
	//函数指针数组指针
	char* (*(*ppp)[3])(const int, double, char*)=&pp;
	printf("%s", test(0,0,0));
	printf("%s", p(0, 0, 0));
	printf("%s", pp[0](0, 0, 0));
	printf("%s", (*ppp)[0](0, 0, 0));
	return;
}

四、回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

大家还记得冒泡排序吗?
但是冒泡排序只能排序整形,而qsort函数,内部采用快速排序,可以排序各种类型的数据,接下来展示qsort排序部分类型的方法.

示例:qsort函数部分应用
分别将元素比较方法int_cmp和char_cmp的指针(地址) 传给 qsot函数.由qsort函数调用这些比较函数.

#include <stdlib.h>
#include <stdio.h>
int int_cmp(void* e1, void* e2)//整形元素排序方法
{
	return *(int*)e1 - *(int*)e2;
}
int char_cmp(void* e1, void* e2)//字符型元素排序方法
{
	return (*(char*)e1) - (*(char*)e2);
}
int main()
{
	int arr1[10] = { 4,5,1,8,9,2,10,3,7,6 };
	char arr2[] = "fbadegc";
	int sz1 = sizeof(arr1) / sizeof(arr1[0]);
	int sz2 = sizeof(arr2) / sizeof(arr2[0]);
	qsort(arr1,sz1,sizeof(arr1[0]),int_cmp);
	for (int i=0; i < sz1; i++)
	{
		printf("%d ", arr1[i]);
	}
	printf("\n");
	qsort(arr2, sz2, sizeof(arr2[0]), char_cmp);
	for (int i = 0; i < sz2; i++)
	{
		printf("%c ", arr2[i]);
	}
	printf("%s", arr2);
	return 0;
}

运行结果:

1 2 3 4 5 6 7 8 9 10
a b c d e f g

qsort函数冒泡排序的模拟实现,以及各种类型的排序.这周会加更出来的,好文不怕晚.🤣🤣🤣
最后,如果文章对大家有帮助的话,求一波三连吧!
💗💗💗886
在这里插入图片描述

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

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

相关文章

shell学习3

目录 一、查找并删除重复文件 二、列举文件类型统计信息 三、只列出目录 一、查找并删除重复文件 重复文件是同一个文件的多个副本。有时候我们需要删除重复的文件&#xff0c;只保留其中一份。通过查看文件内容来识别重复文件是件挺有意思的活儿。可以结合多种shell工具来完…

阶段六:服务框架基础(第二章Day-MQ(服务异步通讯))

阶段六&#xff1a;服务框架基础&#xff08;第二章Day-MQ&#xff08;服务异步通讯&#xff09;&#xff09;Day-RabbitMQ1.初识MQ1.1.同步和异步通讯1.1.1.同步通讯1.1.2.异步通讯1.2.技术对比&#xff1a;2.快速入门2.1.安装RabbitMQ 【重要】2.1.1、安装RabbitMQ&#xff0…

换掉 Maven,我就用Gradle,急速编译

相信使用Java的同学都用过Maven&#xff0c;这是一个非常经典好用的项目构建工具。但是如果你经常使用Maven&#xff0c;可能会发现Maven有一些地方用的让人不太舒服&#xff1a; Maven的配置文件是XML格式的&#xff0c;假如你的项目依赖的包比较多&#xff0c;那么XML文件就…

[Datawhale][CS224W]图机器学习(六)

目录一、简介二、概述三、算法四、PageRank的缺点五、Python实现迭代法参考文献一、简介 PageRank&#xff0c;又称网页排名、谷歌左侧排名、PR&#xff0c;是Google公司所使用的对其搜索引擎搜索结果中的网页进行排名的一种算法。 佩奇排名本质上是一种以网页之间的超链接个…

蒙特卡洛随机模拟

蒙特卡洛随机模拟 简介 蒙特卡洛模拟是在计算机上模拟项目实施了成千上万次&#xff0c;每次输入都随机选择输入值。由于每个输入很多时候本身就是一个估计区间&#xff0c;因此计算机模型会随机选取每个输入的该区间内的任意值&#xff0c;通过大量成千上万甚至百万次的模拟…

笔记本触摸板没反应怎么办?处理方法看这些

触摸板在笔记本电脑中是非常重要的一部分&#xff0c;很多用户都会选择使用触摸板代替鼠标。然而&#xff0c;有时你可能会发现&#xff0c;你的笔记本电脑触摸板没反应&#xff0c;无法正常使用。这对于日常使用来说是非常困扰的&#xff0c;但不用担心&#xff0c;我们将在这…

JavaScript BOM【快速掌握知识点】

目录 Window对象的常用属性 语法&#xff1a; Window对象的常用方法 语法&#xff1a; open()和close()方法 History对象 常用属性和方法 示例 Location对象 常用属性 常用方法 Document对象的常用方法 定时函数 超时调用&#xff1a;setTimeout() 间歇调用&…

插件化框架shadow——腾讯

theme: cyanosis Shadow简介 Shadow是最近腾讯开源的一款插件化框架。原理是使用宿主代理的方式实现组件的生命周期。目前的插件化框架&#xff0c;大部分都是使用hook系统的方式来做的。使用代理的基本上没有成体系的框架&#xff0c;只是一些小demo&#xff0c;Shadow框架的…

【华为OD机试模拟题】用 C++ 实现 - 查找单入口空闲区域(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明查找单入口空闲区域题目输入输出示例一输入输出说明示例二输入输出说明示例三输入输出说明示例

在linux中web服务器的搭建与配置

以下涉及到的linux命令大全查阅 https://www.runoob.com/linux/linux-command-manual.htmlvim命令查阅 https://www.runoob.com/linux/linux-vim.htmlscp命令https://www.runoob.com/linux/linux-comm-scp.html首先要有一个请求的服务地址用ssh 进入到linux系统中ssh 请求的服务…

JavaWeb Servlet Cookie和Session

6、Servlet 6.1、Servlet简介 Servlet就是sun公司开发动态web的一门技术Sun在这些API中提供一个接口叫做&#xff1a;Servlet&#xff0c;如果你想开发一个Servlet程序&#xff0c;只需要完成两个小步骤&#xff1a; 编写一个类&#xff0c;实现Servlet接口把开发好的Java类部…

Redis 4种集群方案介绍+优缺点对比

前言在服务开发中&#xff0c;单机都会存在单点故障的问题&#xff0c;即服务部署在一台服务器上&#xff0c;一旦服务器宕机服务就不可用&#xff0c;所以为了让服务高可用&#xff0c;分布式服务就出现了&#xff0c;将同一服务部署到多台机器上&#xff0c;即使其中几台服务…

【LeetCode】剑指 Offer 17. 打印从1到最大的n位数 p114 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/da-yin-cong-1dao-zui-da-de-nwei-shu-lcof/ 1. 题目介绍&#xff08;17. 打印从1到最大的n位数&#xff09; 输入数字 n&#xff0c;按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3&#xff0c;则打印出 1、2、3 一直…

<JVM上篇:内存与垃圾回收篇>12 - 垃圾回收相关概念

笔记来源&#xff1a;尚硅谷 JVM 全套教程&#xff0c;百万播放&#xff0c;全网巅峰&#xff08;宋红康详解 java 虚拟机&#xff09; 文章目录12.1. System.gc()的理解12.2. 内存溢出与内存泄露内存溢出&#xff08;OOM&#xff09;内存泄漏&#xff08;Memory Leak&#xff…

【Linux驱动开发100问】Linux驱动开发工程师在面试中常被问到的问题汇总

&#x1f947;今日学习目标&#xff1a;什么是Kconfig&#xff1f;如何使用Kconfig&#xff1f; &#x1f935;‍♂️ 创作者&#xff1a;JamesBin ⏰预计时间&#xff1a;10分钟 &#x1f389;个人主页&#xff1a;嵌入式悦翔园个人主页 &#x1f341;专栏介绍&#xff1a;Lin…

针对面试官的盘问-如何回答职场中的一些问题

(点击即可收听)初入职场,面对面试官的提问,如何回答01你为什么从上家公司离职?个人成长不足,不符合自己的预期&#xff08;关系到个人竞争力,希望找到一份更有挑战,个人提升更大的工作&#xff09;,切忌与面试官倒苦水,说前公司老板的不是业务发展缓慢,上升空间有限(有些不符合…

【华为OD机试模拟题】用 C++ 实现 - 不等式(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明不等式题目输入输出描述示例一输入输出示例二输入输出Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD …

正态分布、Q函数、误差函数erf()和互补误差函数erfc()

1、正态分布&#xff08;高斯分布&#xff09; 若随机变量 X服从一个位置参数为 μ、尺度参数为 σ 的概率分布&#xff0c;且其概率密度函数为 则这个随机变量就称为正态随机变量&#xff0c;正态随机变量服从的分布就称为正态分布&#xff0c;记作 X∼N(μ,σ2) 。 当μ0,σ…

【Opencv-python】之入门安装

目录 一、安装Python 1. 登录官网https://www.python.org/downloads/ 2. 任选一个版本&#xff0c;下载Python 3. 安装Python 记得勾选下图的Add Python 3.6 PATH, 添加python到环境变量的路径&#xff0c;然后选择Install now​编辑 4. 验证是否安装成功 5.退出 二、安装…

【华为OD机试模拟题】用 C++ 实现 - 路灯照明(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明路灯照明【华为OD机试模拟题】题目输入输出描述示例一输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高…