拿捏指针(三)

news2025/2/26 23:13:08

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就可以了。

结尾 

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

 

 

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

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

相关文章

Centos7部署使用TELEMAC-MASCARET

Background TELEMAC-MASCARET是一款研究水动力学和水文学领域的高性能数值仿真开源软件。MASCARET&#xff08;1980&#xff09;和 TELEMAC&#xff08;1987&#xff09;最初是由法电集团所属的法国国立水利与环境实验室开发&#xff0c;随后整合为TELEMAC-MASCARET并由法英德三…

后端系统开发之——创建注册接口

原文地址&#xff1a;后端系统开发之——创建注册接口 - Pleasure的博客 下面是正文内容&#xff1a; 前言 这是一篇SpringBoot项目的实践篇。 主要用于介绍如何从零开始搭建某一种类型的系统。 个人认为&#xff0c;只要后端逻辑完善了&#xff0c;纵使前端页面千变万化都可…

【DL经典回顾】激活函数大汇总(二十四)(Absolute附代码和详细公式)

激活函数大汇总&#xff08;二十四&#xff09;&#xff08;Absolute附代码和详细公式&#xff09; 更多激活函数见激活函数大汇总列表 一、引言 欢迎来到我们深入探索神经网络核心组成部分——激活函数的系列博客。在人工智能的世界里&#xff0c;激活函数扮演着不可或缺的…

个人开发者上架App流程

摘要 个人开发者完全可以将自己开发的App上传至应用商店进行上架。本文将介绍上架流程的通用步骤&#xff0c;包括确定App功能和定位、准备相关资料、开发App、提交审核、发布App和宣传推广等内容。 引言 个人开发者在如今的移动应用市场中也有机会将自己的作品推向更广泛的…

【书生·浦语大模型实战营】学习笔记3

文章目录 1. 大模型开发范式2. LangChain简介3. 构建向量数据库4. 搭建知识库助手5. Web Demo部署6. 动手实战环节环境配置知识库搭建InternLM接入LangChain构建检索问答链部署Web Demo 参考资料 1. 大模型开发范式 LLM局限性&#xff1a; 知识时效性&#xff1a;LLM无法获取最…

【Vue3】组件通信的的各种方式和tsx风格

组件通信 Vue2组件通信方式全局事件总线bus&#xff0c;可以实现组件通信 Vue3组件通信方式propsprovide与inject依赖注入 全局APiVue3其他改变组件通信之自定义事件组件通信之事件总线组件通信之v-model多个v-model传值 TSX风格使用风格一使用tsx风格&#xff0c;使用optionsA…

V-JEPA模型,非LLM另外的选择,AGI的未来:迈向Yann LeCun先进机器智能(AMI)愿景的下一步

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Flink源码解析(1)job启动,从JM到TM过程详解

网络传输模型 首先在看之前,回顾一下akka模型: Flink通讯模型—Akka与Actor模型-CSDN博客 注:ActorRef就是actor的引用,封装好了actor 下面是jm和tm在通讯上的概念图: RpcGateway 不理解网关的作用,可以先移步看这里:网关_百度百科 (baidu.com) 用于定义RPC协议,是…

JS11-scroll相关属性和缓动动画

scroll 相关属性 window.onscroll() 方法 当我们用鼠标滚轮&#xff0c;滚动网页的时候&#xff0c;会触发 window.onscroll() 方法。效果如下&#xff1a;&#xff08;注意看控制台的打印结果&#xff09; 如果你需要做滚动监听&#xff0c;可以使用这个方法。 我们来看看和…

用C语言打造自己的Unix风格ls命令

在Unix或类Unix操作系统中&#xff0c;ls是一个非常基础且实用的命令&#xff0c;它用于列出当前目录或指定目录下的文件和子目录。下面&#xff0c;我们将通过C语言编写一个简化的ls命令&#xff0c;展示如何利用dirent.h头文件提供的函数接口实现这一功能。 #include "…

开始喜欢上了runnergo,JMeter out了?

RunnerGo是一款基于Go语言、国产自研的测试平台。它支持高并发、分布式性能测试。和JMeter不一样的是&#xff0c;它采用了B/S架构&#xff0c;更灵活、更方便。而且&#xff0c;除了API测试和性能测试&#xff0c;RunnerGo还加上了UI测试和项目管理等实用功能&#xff0c;让测…

Jenkins Pipeline中when的用法

目录 概述内置条件branchbuildingTagchangesetchangeRequestequalsexpressiontriggeredBytagenvironmentnotallOfanyOf 在进入 stage 的 agent 前评估 whenbeforeAgentbeforeInputbeforeOptions 示例单一条件、声明性流水线多条件、声明式管道嵌套条件&#xff08;与前面的示例…

综合实验---Web---进阶版

目录 实验配置&#xff1a; 1.PHP调整主配置文件时&#xff0c;修改文件内容 1.原内容调整(在编译安装的情况下) 2.调整如下 3.没有调整的&#xff0c;根据之前配置就行 2.配置Nginx支持PHP解析 1.原内容如下 2.调整如下 3.验证PHP测试页 1.原内容如下 2.调整如下 4…

U盘安装Linux系统报dracut-initqueue错误,解决方案

U盘安装Linux系统报dracut-initqueue错误&#xff0c;是因为系统所在U盘路径不对&#xff0c;需要修改 解决方法&#xff1a; dracut:/# cd dev >dracut:/# ls |grep sdb 查看你的u盘是哪个一般是sdbX,X是一个数字&#xff0c;也有可能是sda等&#xff0c;如果上边都不对…

C语言数据结构基础——二叉树学习笔记(二)topk问题

1.top-k问题 1.1思路分析 TOP-K 问题&#xff1a;即求数据结合中前 K 个最大的元素或者最小的元素&#xff0c;一般情况下数据量都比较大 。 比如&#xff1a;专业前 10 名、世界 500 强、富豪榜、游戏中前 100 的活跃玩家等。 对于 Top-K 问题&#xff0c;能想到的最简单直…

词令微信小程序怎么添加到我的小程序?

微信小程序怎么添加到我的小程序&#xff1f; 1、找到并打开要添加的小程序&#xff1b; 2、打开小程序后&#xff0c;点击右上角的「…」 3、点击后底部弹窗更多选项&#xff0c;请找到并点击「添加到我的小程序」&#xff1b; 4、添加成功后&#xff0c;就可以在首页下拉我的…

代码随想录算法训练营第二十七天 |131.分割回文串,一些思考

实际上&#xff0c;分割子集问题也是组合问题 &#xff08;图源代码随想录网站&#xff09; 一个套路&#xff0c;也就是说&#xff0c;每次递归函数参数列表传入start的时候&#xff0c;选中的元素相当于是在最后面划了一条分割线 回文子串的判断剪枝操作就很简单了&#xf…

AIGC元年大模型发展现状手册

零、AIGC大模型概览 AIGC大模型在人工智能领域取得了重大突破&#xff0c;涵盖了LLM大模型、多模态大模型、图像生成大模型以及视频生成大模型等四种类型。这些模型不仅拓宽了人工智能的应用范围&#xff0c;也提升了其处理复杂任务的能力。a.) LLM大模型通过深度学习和自然语…

什么是闭包?闭包的优缺点?闭包的应用场景?

什么是闭包&#xff1f; 闭包是指有权访问另外一个函数作用域中的变量的函数。 闭包形成的必要条件&#xff1a; 函数嵌套内部函数使用外部函数的变量内部函数作为返回值 举个栗子&#xff1a;实现每隔1s递增打印数字 使用闭包实现 for(var i1; i<5; i) {(function(i) {se…

Cointelegraph 策略主管 JASON CHOI确认出席Hack.Summit() 2024区块链开发者大会

随着区块链技术的蓬勃发展和广泛应用&#xff0c;一场备受瞩目的盛会即将拉开帷幕。Hack.Summit() 2024区块链开发者大会&#xff0c;由Hack VC主办&#xff0c;AltLayer和Berachain协办&#xff0c;Solana、The Graph、Blockchain Academy、ScalingX、0G、SNZ和数码港等机构的…