拿捏指针(三)

0f3a2b8bed084b1488aef3e7406bf5b9.jpeg

✨✨欢迎👍👍点赞☕️☕️收藏✍✍评论

个人主页:秋邱'博客

所属栏目:C语言

(感谢您的光临,您的光临蓬荜生辉)

 前言

在这之前我们学习了《拿捏指针(一)》,《拿捏指针(二)》没看过的可以去看看哟,接下里我们将指针最后一篇,《拿捏指针(三)》,看完直接捏爆指针。

函数

前面我们已经学过了指针函数,接下里学指针数组,回调函数。

我们先来看看下面这串代码。

计算器

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
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 Div(int x, int y)
{
	return x / y;
}
int main()
{
    int x, y;
    int ret = 0;
    int input = 0;
    do
    {
        printf("************************\n");
        printf("***** 1.Add  2.Sub *****\n");
        printf("***** 3.Mul  4.Div *****\n");
        printf("*******  0.exit  *******\n");
        printf("************************\n");
        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);
        case 0:
            printf("退出程序\n");
                break;
        default:
            printf("输入错误\n");
        }
        
    } while (input);
}

虽然我们实现了这个计算器,但是它太过于累赘了,这是我们就可以用函数指针数组。

函数指针数组

数组是⼀个存放相同类型数据的存储空间,我们已经学习了指针数组,那要把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组

其实在《拿捏指针(二)》的模拟二维数组里面,我们已经用过函数指针数组了。

定义的格式

int (*p[3])();

 p先和 [] 结合,说明parr1是数组,是 int (*)() 类型的函数指针。

我们现在对上面的代码进行,更改用函数指针数组的方式。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
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 Div(int x, int y)
{
	return x / y;
}
int main()
{
    int x, y;
    int ret = 0;
    int input = 0;
    int(*p[5])(int x, int y) = { 0, Add, Sub, Mul, Div };
    do
    {

        printf("************************\n");
        printf("***** 1.Add  2.Sub *****\n");
        printf("***** 3.Mul  4.Div *****\n");
        printf("*******  0.exit  *******\n");
        printf("************************\n");
        printf("请选择:");
        scanf("%d", &input);
        if ((input <= 4 && input >= 1))
        {
            printf("输⼊操作数:" );
            scanf("%d %d", &x, &y);
            ret = (*p[input])(x, y);
            printf("ret = %d\n", ret);
        }
        else if (input == 0)
        {
            printf("退出计算器\n");
        }
        else
        {
            printf("输⼊有误\n" );        
        }
    } while (input);
 
}

回调函数

回调函数是一个函数,它作为参数传递给另一个函数,在特定事件发生时被调用。这种机制允许我们将代码模块化,并在需要的时候进行调用。回调函数常用于事件处理、异步编程、并发编程等场景。

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 Div(int x, int y)
{
	return x / y;
}
void calc(int(*pf)(int, int))//回调函数
{
    int ret = 0;
    int x, y;
    printf("输⼊操作数:");
    scanf("%d %d", &x, &y);
    ret = pf(x, y);
    printf("ret = %d\n", ret);
}
int main()
{
    int input = 1;
    do
    {
        printf("************************\n");
        printf("***** 1.Add  2.Sub *****\n");
        printf("***** 3.Mul  4.Div *****\n");
        printf("*******  0.exit  *******\n");
        printf("************************\n");
        switch (input)
        {
        case 1:
            calc(Add);//调用函数
            break;
        case 2:
            calc(Sub);//调用函数
            break;
        case 3:
            calc(Mul);//调用函数
            break;
        case 4:
            calc(Div);//调用函数
            break;
        case 0:
            printf("退出程序\n");
                break;
        default:
            printf("选择错误\n");
                break;
        }
    } while (input);

}

qsort()函数

冒泡排序

什么事冒泡排序呢?

冒泡排序是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。

动图演示 

我们就用c语言来实现它。

void Swap(int* arr, int sz)
{
	for (int i = 0; i < sz -1; i++)
	{
		for (int j = 0; j < sz - i -1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
int main()
{
	int arr[10] = { 3,6,8,1,9,4,2,7,10,5 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Swap(arr,sz);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

 输出结果:


 1 2 3 4 5 6 7 8 9 10

这就是冒泡排序的C语言的实现方式,但是它的局限性太多了,比如你要用字符串呢,这就很难实现,所以我们可以用一个函数就是qsort()。

qsort()函数举例

我们先来看看qsort()的声明

void qsort (void* base, size_t num, size_t size,
            int (*compar)(const void*,const void*));

base       指向数组中要排序的第一个对象的指针,转换为void*。

num       基数指向的数组中元素的个数。Sizet是一个无符号整型。

size        数组中每个元素的字节大小。Size t是一个无符号整型。

compar 指向比较两个元素的函数的指针。这个函数被qsort反复调用以比较两个元素。应遵                循以下原型:Int compare (const void* p1, const void* p2)。

 下面我们来对它进行使用

排序整型数据

//整形数据结构
int int_arr(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);
}
int main()
{
	int arr[10] = { 3,6,8,1,9,4,2,7,10,5 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr,sz,sizeof(arr),int_arr);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

排序结构数据

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<string.h>//strcmp函数的头文件
#include<stdlib.h>//qsort函数的头文件
struct people {
	char name[20];
	int age;
};
//数据结构名字比较
int cmp_name(const void* e1, const void* e2)
{
	return strcmp(((struct people*)e1)->name, ((struct people*)e2)->name);
}

//打印
void Print(struct people* p1,int sz)
{
	for (int i = 0; i < sz; i++)
	{
		/*printf("%s %d\n", p1[i].name, p1[i].age);//另一种打印方式*/
		printf("%s %d\n", (p1 + i)->name, (p1 + i)->age);
	}
	printf("\n");
}
//数据结构年龄比较
int cmp_age(const void* e1, const void* e2)
{
	return ((struct people*)e1)->age - ((struct people*)e2)->age;
}
int main()
{
	struct people s[] = { {"tangsan",20},{"lisi",10},{"zhaowu",40},{"laoliu",5} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_name);
	printf("按名字排序\n");
	Print(s, sz);
	qsort(s, sz, sizeof(s[0]), cmp_age);
	printf("按年龄排序\n");
	Print(s,sz);
	return 0;
}

输出结果:

按名字排序
laoliu 5
lisi 10
tangsan 20
zhaowu 40

按年龄排序
laoliu 5
lisi 10
tangsan 20
zhaowu 40

 

qsort()的模拟

上面我们已经知道了qsort函数的定义和使用,现在我们就来模拟一下qsort函数。

//实现qsort函数
void Swap(char* p1, char* p2,size_t width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++;
		p2++;
	}
}
int bubbl_sort(void* base, size_t num,size_t width,int cmp (const void*p1 ,const void* p2))
{
	for (int i = 0; i < num - 1; i++)
	{
		for (int j = 0; j < num - 1 - i; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
			}
		}
	}
}
int int_cmp(const void* p1, const void* p2)
{
	return *(char*)p1 - *(char*)p2;
}

int main()
{
	int base[10] = {2, 7, 3, 8, 1, 9, 1, 5, 6, 0};
	int sz = sizeof(base) / sizeof(base[0]);
	bubbl_sort(base,sz,sizeof(base[0]),int_cmp );
	for (int i = 0; i < sizeof(base) / sizeof(base[0]); i++)
	{
		printf("%d ", base[i]);
	}
	printf("\n");
	return 0;
}

我们这里展现int型的排序。 

sizeof和strlen的对⽐

sizeof

前面我们也已经讲过了sizeof,现在我们再来简单的回顾一下,sizeof是一个操作符,用来计算类型的大小,单位是字节。

注意:
sizeof只与类型有关,跟内容没什么关系

int main()
{
	int a = 10;
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof a);
	printf("%d\n", sizeof(int));
	return 0;
}

输出结果:

4

4

strlen

strlen 是C语⾔库函数,功能是求字符串⻓度。函数原型如下:

size_t strlen ( const char * str );

统计的是从 strlen 函数的参数 str 中这个地址开始向后,\0 之前字符串中字符的个数。 strlen 函数会⼀直向后找 \0 字符,直到找到为⽌,所以可能存在越界查找。

int main()
{
	char arr1[3] = { 'a', 'b', 'c' };
	char arr2[] = "abc";
	printf("arr1=%d\n", strlen(arr1));
	printf("arr2=%d\n", strlen(arr2));
}

输出结果:

arr1=(随机值,直到遇到\0后停下来)

arr2=3

char arr1[3] = { 'a', 'b', 'c' ,\0"};

这时只需要在后面手动改加上/0就可以了。

结尾 

我们指针以及全部将完了,感谢各位观众老爷的点赞,评论,收藏和关注。

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ansible基本介绍与模块使用

目录 引言 一、Ansible简介 &#xff08;一&#xff09;基本概述 &#xff08;二&#xff09;主要特点 二、Ansible安装及基本组件 &#xff08;一&#xff09;yum安装 &#xff08;二&#xff09;编译安装 &#xff08;三&#xff09;基本配置信息 1.主配置文件 2.主…

【Linux】自动化构建工具-make/Makefile

个人主页 &#xff1a; zxctscl 如有转载请先通知 文章目录 1. 前言2. 认识make/Makefile3. 了解make/Makefile原理3.1 依赖关系和依赖方法3.2 make检测的顺序3.3 PHONY:XXX 4. makefile内置符号 1. 前言 在上一篇中已经了解了【Linux】编译器-gcc/g使用&#xff0c;这次来一起…

01|模型IO:输入提示、调用模型、解析输出

Model I/O 可以把对模型的使用过程拆解成三块&#xff0c;分别是输入提示&#xff08;对应图中的Format&#xff09;、调用模型&#xff08;对应图中的Predict&#xff09;和输出解析&#xff08;对应图中的Parse&#xff09;。这三块形成了一个整体&#xff0c;因此在LangCha…

idea将非UTF-8的properties修改为UTF-8编码的文件

需求背景 由于项目初始化时&#xff0c;properties文件的编码格式为ASCII编码格式&#xff0c;此时用idea打开该文件会默认展示UTF-8的编码内容&#xff0c;其中汉字可以正常展示&#xff0c;但是使用notepad打开却依旧时ASCII编码格式 idea配置 打开idea-setting-editor-f…

TCP - 传输控制协议

TCP - 传输控制协议 是一种面向连接的可靠传输协议。 特点&#xff1a; TCP是面向连接&#xff08;虚连接&#xff09;的传输层协议。 每一条TCP连接有且只能有两个端点。 可靠、有序、无丢弃和不重复。 TCP协议提供全双工通讯。 发送缓存 存放发送方TCP准备发送的数据。T…

Springboot笔记-01

简化spring应用开发&#xff0c;约定大于配置 简化Spring应用开发的一个框架&#xff1b; 整个Spring技术栈的一个大整合&#xff1b; J2EE开发的一站式解决方案&#xff1b; 优点&#xff1a; 快速创建独立运行的spring项目以及于主流框架集成 使用嵌入式的Servlet容器&#x…

Reactor线程模型

线程模型 一、背景1.socket网络通信2.IO模型与线程模型3.线程模型分类3.1 阻塞模型3.2 Reactor模型3.3 Proactor模式 二、阻塞模型1.代码示例 三、Reactor模型1.单Reactor单线程1.1 处理过程1.2 优缺点1.3 代码示例 2.单Reactor多线程2.1 处理机制2.2 优缺点 3.主从Reactor3.1 …

深度学习_卷积

卷积 卷积&#xff08;Convolution&#xff09;是数学和计算机科学中的一个重要概念&#xff0c;特别在信号处理和图像处理中应用广泛。在信号处理领域&#xff0c;卷积是两个函数之间的一种数学操作&#xff0c;它表示两个函数的重叠部分的积分量。 在图像处理中&#xff0c…

JavaScript数组排序sort自定义函数不生效

背景 刷LeetCode时&#xff0c;遇到一道简单的数组排序题&#xff1a; 问题 想着直接用js的数组sort自定义排序即可&#xff0c;奈何测试用例运行总是不通过&#xff0c;返回的一直都是原数组。 代码排查 复制代码到Firefox浏览器控制台运行&#xff0c;结果输出的是正确结果&a…

搭建Hadoop集群(完全分布式运行模式)

目录 一、准备模板机(最小化安装)二、配置一台纯净的模板机修改主机名固定IP地址通过yum安装方式安装必要的软件关闭防火墙且禁止自启修改hosts映射文件创建普通用户 并让他能用sudo命令在/opt下创建software和module完成 三、搭建完全分布式运行模式3.1克隆第一台机器hadoop10…

基于PCA(主成分分析)的人面识别,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

Vue学习日记 Day7 —— json-server工具、基于VueCli自定义创建项目、postcss插件

一、前一天Vuex总结 1、state作用&#xff1a;存放数据定义&#xff1a;state:{//数据 }使用&#xff1a;//放在data下(1)根节点直接访问this.$store.state.数据名(2)模块直接访问this.$store.state.模块名.数据名(3)根节点辅助函数mapState([所需要的数据])(4)模块辅助…

JDK21虚拟线程

目录 虚拟线程 话题 什么是平台线程&#xff1f; 什么是虚拟线程&#xff1f; 为什么要使用虚拟线程&#xff1f; 创建和运行虚拟线程 使用线程类和线程创建虚拟线程。生成器界面 使用Executor.newVirtualThreadPerTaskExecutor&#xff08;&#xff09;方法创建和运行…

【一】【单片机】有关LED的实验

点亮一个LED灯 根据LED模块原理图&#xff0c;我们可以知道&#xff0c;通过控制P20、P21...P27这八个位置的高低电平&#xff0c;可以实现D1~D8八个LED灯的亮灭。VCC接的是高电平&#xff0c;如果P20接的是低电平&#xff0c;那么D1就可以亮。如果P20接的是高电平&#xff0c;…

CSS基础属性(学习笔记)

一、CSS介绍 CSS即层叠样式表/级联样式表&#xff0c;简称样式表 html&#xff1a;写网页结构内容 css&#xff1a;写网页样式 实现了内容与表现的分离&#xff0c;提高了代码的重用性和维护性 CSS注释不被浏览器解析&#xff0c;给开发人员一个标注 快捷键&#xff1a;ctrl/ 语…

YOLOv5独家改进:block改进 | RepViTBlock和C3进行结合实现二次创新 | CVPR2024清华RepViT

💡💡💡本文独家改进:CVPR2024 清华提出RepViT:轻量级新主干!从ViT角度重新审视移动CNN,RepViTBlock和C3进行结合实现二次创新 改进结构图如下: 收录 YOLOv5原创自研 https://blog.csdn.net/m0_63774211/category_12511931.html 💡💡💡全网独家首发创…

FTP文件传输协议

FTP 文章目录 FTP1. ftp简介2. ftp架构3. ftp数据连接模式4. 用户认证5. vsftpd5.1 vsftpd安装5.2 配置匿名用户ftp5.2.1上传&#xff08;下面使用的是FileZilla软件&#xff09;5.2.2下载5.2.3创建5.2.4删除 5.3配置本地&#xff08;系统&#xff09;用户ftp5.3.1上传5.3.2下载…

Qt教程 — 3.4 深入了解Qt 控件:Input Widgets部件(3)

目录 1 Input Widgets简介 2 如何使用Input Widgets部件 2.1 Dial 组件-模拟车速表 2.2 QScrollBar组件-创建水平和垂直滚动条 2.3 QSlider组件-创建水平和垂直滑动条 2.4 QKeySequenceEdit组件-捕获键盘快捷键 Input Widgets部件部件较多&#xff0c;将分为三篇文章介绍…

网络基础知识-DNS与DHCP+网络规划与设计故障诊断+嵌入式系统设计师备考笔记

0、前言 本专栏为个人备考软考嵌入式系统设计师的复习笔记&#xff0c;未经本人许可&#xff0c;请勿转载&#xff0c;如发现本笔记内容的错误还望各位不吝赐教&#xff08;笔记内容可能有误怕产生错误引导&#xff09;。 本章的主要内容见下图&#xff1a; 本章知识和计算机…

创意二维码营销案例:帕森斯设计学院在巴黎市中心搭建“沙滩度假地”

作为一个专业的艺术设计学院&#xff0c;帕森斯设计学院&#xff08;Parsons School of Design, The New School&#xff09;以其卓越的教学质量和创新的设计理念享誉全球。 每年的夏天&#xff0c;帕森斯设计学院都会举办一个暑期短期项目&#xff0c;面向全球学生&#xff0…