模拟实现C语言中经典库函数,字符相关的函数与内存相关的函数

news2024/11/26 3:21:17
  • 前言:C语言中拥有非常多的库函数,仅仅知道它们是不够的,在知道它们的原理后,去模拟实现它能够帮助我们更好的掌握这些库函数。
    PS(在面试时,部分企业会让你来模拟实现一些库函数)

文章目录:模拟库函数的实现

  • 模拟实现strcmp
  • 模拟实现strcat
  • 模拟实现strstr
  • 模拟实现memcpy
  • 模拟实现memmove
    • 序言

查找库函数的网站

模拟实现strcmp

在模拟实现一个库函数之前,我们要先了解这个库函数的作用
这里我们可以通过这个查看C语言库函数的网站去查找:查找库函数
在这里插入图片描述
由此我们可以知道,strcmp的作用是将俩个字符串相比较,如果前者比后者长则返回大于0的数,反正则返回小于0的数,相等则返回等于0的数

代码实现思路:

分为三种情况:
①俩者所有字符全部相等 --> 返回0
②前者比后者小 --> 返回 -1
③前者比后者大 --> 返回1

代码实现:

#include <stdio.h>
#include <assert.h>
//模拟实现strcmp
int my_strcmp(const char* str1, const char* str2)//用const修饰防止传过来的指针值被修改
{
	assert(str1 && str2);//放在传过来的是空指针
	while (*str1++ == *str2++)//如果字符相等则进入循环看它们是否一一对应相等
	//如果不相等则跳出循环
	{
		if (*str1 == '\0')//如果*str1等于'\0'时,说明俩个字符串全部遍历完并且一一对应相等
			return 0;
	}
	if (*str1 > *str2)//如果不相等判断字符的大小,前置大则返回1
		return 1;
	else
		return -1;
}
int main()
{
	char arr1[100] = {0};
	char arr2[100] = {0};
	gets(arr1);
	gets(arr2);
	int ret = my_strcmp(arr1, arr2);//保存返回值
	printf("%d\n", ret);
	return 0;
}

运行结果:
在这里插入图片描述

模拟实现strcat

还是一样的,在实现一个库函数之前,先了解该库函数的作用
在这里插入图片描述
注:将一个字符串,拼接到另一个字符串后面,该字符串不能是同一个字符串,并返回目标字符串的地址。

代码实现思路:

  • 找到目标空间地址的尾部
  • 将另一个字符串衔接上去
    代码实现:
//模拟实现strcat
char* my_strcat(char* str1, char* str2)
{
	//1.找到目标地址的尾部
	//2.衔接上去
	assert(str1 && str2);
	char* tmp = str1;//保留目标空间的起始地址
	while (*str1++)//找到目标地址的尾部'\0'
	{
		if (*str1 == '\0')//找到'\0'
		{
			while ( *str1++ = *str2++)//将地址衔接上去
			{
				;
			}
		}
	}
	return tmp;
}
int main()
{
	char arr1[100] = {0};
	char arr2[100] = {0};
	gets(arr1);
	gets(arr2);
	my_strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

运行结果:
在这里插入图片描述

模拟实现strstr

工欲善其事,必先利其器。如果我们想做好一件事,首先就要做好充分的准备工作。所以我们先了解其作用再来实现!
在这里插入图片描述
其作用是:在一个字符串中,找另一个字符串,如果没有找到则返回NULL,找到了就返回该字符串,并将原函数中该字符串后面的结果一并输出。

代码实现思路:

s1,s2(都是俩个字符串的指针)代表在s1中找s2
在这里插入图片描述
如果我们让s1,s2直接向匹配我们会发现,我们哪怕找到了想对应的字符,但是由于s1是不断的在往后走,我们并不能直接找到字符在相等的时候的位置,此时我们想要在通过原本的指针去找到相等的起始位置是十分困难的。因此,我们需要在引入一个指针去帮住我们记录下当俩个字符串完全相等的时候的起始地址。
在这里插入图片描述
我们让指针cp帮我们早到原本的地址,让s1去判断是否相等,让字符完全匹配时,返回cp的地址即可在这里插入图片描述

代码实现:

//模拟实现strstr
const char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* cp;//记录开始匹配的位置
	const char* s1;//记录str1的位置
	const char* s2;//记录str2的位置
	if (*str2 == '\0')
	{
		return str1;
	}
	cp = str1;//让cp去记录开始匹配的位置
	while (*cp)
	{
		s1 = cp;
		s2 = str2;//让s2代替原本的str2去动
		while (*s1 && *s2 && *s1 == *s2)//s1,s2 !='\0' 并且s1 == s2
		{
			//找到它们的相同值,看他是否对应
			s1++;
			s2++;
		}
		if(*s2 == '\0')//如果全部找完,发现s2是'\0'说明找到了
		{
			return cp;//返回之前所留的cp记录的就是一开始的位置
		}
		cp++;//如果没有找到,就让cp往后加一继续重复刚刚的过程
	}
	return NULL;//如果全部运行了都没找到说明没有找到,返回空指针;
}
int main()
{
	char arr1[] = "mnabbbefghij";
	char arr2[] = "bbb";
	char* ret = my_strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

运行结果:
在这里插入图片描述

模拟实现memcpy

依然来先看该库函数的作用:在这里插入图片描述
可以将任意同类型的数据,拷贝到另一个同类型的数据中去,但不能拷贝重叠内存

代码实现思路:

首先在实现的过程中,我们要知道,我们并不知道使用者会传过来什么类型的数据,因此我们在实现的过程中用俩个 void* 类型的指针来接受,并且我们要让使用者传过来他所需要拷贝的数据有多少字节。为什么需要知道字节?因为我们并不知道它的类型,我们将传过来的地址转换成char*类型,让它一次加1走一个字节俩俩交换,就能实现任意数据的交互了。
在这里插入图片描述

代码实现:

//模拟实现memcpy -- 不重叠的内存拷贝可以使用memcpy 
void* my_memcpy(void* arr1, const void* arr2, size_t num)
{
	char* tmp = arr1;
	assert(arr1 && arr2);
	while (num--)
	{
		*(char*)arr1 = *(char*)arr2;//强制类型转换是一种临时变量
		arr1 = (char*)arr1 + 1;//让它们一次走一个字节,走一次交换换一次
		arr2 = (char*)arr2 + 1;
	}//全部字节交换完成后它们的地址也就全部交换完成了
	return tmp;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6 };
	int arr2[] = { 0,9,2,2,9 };
	my_memcpy(arr1, arr2, 16);
	int i = 0;
	for (i = 0; i < 6; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

运行结果:在这里插入图片描述

模拟实现memmove

还是老规矩,运行代码之前先来看它的作用
在这里插入图片描述
前面我们说讲的memcpy可以拷贝同类型的数据,但不能拷贝重叠内存,而这个库函数就可以完美实现拷贝重叠内存

代码实现思路:

我们要知道在同一个数据中拷贝数据的时候会出现俩种情况:
①把低地址的值覆盖到高低址在这里插入图片描述
②把高地址的值覆盖到低地址
因此我们要对俩种情况进行分类讨论

代码实现:

//模拟实现memmove -- 可以拷贝重叠内存
void* my_memove(void* dest, void* src, size_t sz)
{
	char* tmp = dest;
	assert(dest && src);
	if (dest < src)//分俩种情况
	{
		//从前向后
		while (sz--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//从后往前
		while (sz--)
		{
		*((char*)dest+sz) = *((char*)src + sz);// 让src与dest找到最后一个数,从后往前赋值
		}
	}
	return tmp;
}
int main()
{
	int arr[] = { 1,3,2,7,8 };
	my_memove(arr+2, arr , 12);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

运行结果:
在这里插入图片描述

序言

成大事不在于力量的大小,而在于能坚持多久。希望各位也能每天坚持学习,能够坚持也就是一种最大的天赋!如若写的不好的地方也希望各位指出。

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

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

相关文章

专栏更新情况:华为流程、产品经理、战略管理、IPD

目录 前言 01 华为流程体系入门课 CSDN学院 02 产品经理进阶课 CSDN学院 03 BLM 战略方法论进阶课 04 IPD 进阶 100 例专栏 作者简介 前言 已上线四大课程专栏更新情况&#xff1a; 01 华为流程体系入门课&#xff08;视频图文&#xff09;&#xff1b; 02 硬件产品经…

C++——list(2)

作者&#xff1a;几冬雪来 时间&#xff1a;2023年9月28日 内容&#xff1a;C——list内容讲解 目录 前言&#xff1a; list的const迭代器&#xff1a; const的iterator&#xff1a; const迭代器&#xff1a; operator->: 拷贝构造&#xff1a; 迭代器接口补充&…

LayoutLMv2:多模态预训练用于富含视觉元素的文档理解【论文翻译】

文章目录 基础信息摘要1 Introduction2 Approach2.1 Model Architecture2.2 2.2 Pre-training TasksMasked Visual-Language ModelingText-Image Alignment (对齐)Text-Image Matching(匹配) 3 Experiments3.1 Data 3.2 SettingsPre-training LayoutLMv2Fine-tuning LayoutLMv2…

初探802.11协议(5)——MIMO/MU-MIMO/OFDMA概念介绍

目录 一. MIMO 1.1 从SISO到MIMO 1.1.1 SISO 1.1.2 SIMO 1.1.3 MISO 1.1.4 MIMO 1.2 MIMO类型 1.3 Wi-Fi MIMO 1.3.1 空间分集 1.3.2 空分复用 二. 从MIMO到MU-MIMO 三. OFDM到OFDMA 四. MU-MIMO vs OFDMA REF 一. MIMO 空间流 (Spatial Stream) &#xff1a;传…

一个简单的敏捷开发的例子

敏捷开发是一种以人为核心、迭代、循序渐进的软件开发方法。 敏捷开发以用户的需求进化为核心&#xff0c;采用迭代、循序渐进的方法进行软件开发。在敏捷开发中&#xff0c;软件项目在构建初期被切分成多个子项目&#xff0c;各个子项目的成果都经过测试&#xff0c;具备可视…

【数据库】存储引擎InnoDB、MyISAM、关系型数据库和非关系型数据库、如何执行一条SQL等重点知识汇总

目录 存储引擎InnoDB、MyISAM的适用场景 关系型和非关系型数据库的区别 MySQL如何执行一条SQL的 存储引擎InnoDB、MyISAM的适用场景 InnoDB 是 MySQL 默认的事务型存储引擎&#xff0c;只有在需要它不支持的特性时&#xff0c;才考虑使用其它存储引擎。实现了四个标准的隔…

Spring事务不生效的场景的解决方案

一、前言 在Java Web开发中&#xff0c;使用Spring框架可以大大简化开发人员的工作。其中&#xff0c;事务管理是Spring框架中的一个重要功能&#xff0c;它可以确保多个数据库操作要么全部成功&#xff0c;要么全部失败。但是&#xff0c;在实际开发中&#xff0c;我们可能会…

【SQLServer语句按月记录总数量】

情景描述&#xff1a;如下表Table_Name有id,name,CreatedDate三个字段.现在需要按照月份记录总数量&#xff0c;得到一个包含月份&#xff0c;数量的表。 select MONTH(CreatedDate) as 月份, COUNT(*) as 数量 from Table_Name group by MONTH(CreatedDate) order by month(C…

JVM调优实战及常量池详解

阿里巴巴Arthas详解 Arthas 是 Alibaba 在 2018 年 9 月开源的 Java 诊断工具。支持 JDK6&#xff0c; 采用命令行交互模式&#xff0c;可以方便的定位和诊断线上程序运行问题。Arthas 官方文档十分详细&#xff0c;详见&#xff1a;https://alibaba.github.io/arthas Arthas…

前端uniapp防止页面整体滑动页面顶部以上,设置固定想要固定区域宽高

解决&#xff1a;设置固定想要固定区域宽高 目录 未改前图未改样式改后图改后样式 未改前图 未改样式 .main {display: flex;flex-direction: row;// justify-content: space-between;width: 100vw;// 防止全部移动到上面位置&#xff01;&#xff01;&#xff01;&#xff01…

排序:堆排序算法分析以及插入删除操作

堆排序可以看作顺序存储的完全二叉树。 堆排序属于选择排序的一种&#xff0c; 选择排序:每一趟在待排序元素中选取关键字最小(或最大&#xff09;的元素加入有序子序列。 1.堆的定义 若n个关键字序列 L [ 1... n ] L[ 1...n] L[1...n]满足下面某一条性质&#xff0c;则称为堆…

【Vue】监控路由与路由参数, 刷新当前页面数据的几种方法

目录 一、Vue监控路由 1、Vue中watch监控路由 2、Vue中watch监控路由的某一个参数 3、Vue中watch同时监控多个路由 二、刷新当前页面数据 1、location.reload 2、$router.go(0) 3、this.$router.resolve()与this.$router.resolve() a、this.$router.resolve() b、thi…

leetcode1610. 可见点的最大数目(java)

可见点的最大数目 题目描述滑动窗口 题目描述 难度 - 困难 leetcode1610. 可见点的最大数目 给你一个点数组 points 和一个表示角度的整数 angle &#xff0c;你的位置是 location &#xff0c;其中 location [posx, posy] 且 points[i] [xi, yi] 都表示 X-Y 平面上的整数坐标…

网络层五大核心知识点

引言 在前面几期文章中&#xff0c;无论是UDP还是TCP&#xff0c;其实我们都在介绍 TCP/IP 模型的“传输层”&#xff0c;我们知道&#xff0c;数据在传输层完成相应的封装后就会来到网络层进行下一步的数据转发&#xff0c;那么数据在网络层又接受了哪些神秘的力量&#xff1…

心法利器[102] | 大模型落地应用架构的一种模式

心法利器 本栏目主要和大家一起讨论近期自己学习的心得和体会&#xff0c;与大家一起成长。具体介绍&#xff1a;仓颉专项&#xff1a;飞机大炮我都会&#xff0c;利器心法我还有。 2022年新一版的文章合集已经发布&#xff0c;累计已经60w字了&#xff0c;获取方式看这里&…

SAP替代物料的解决方案详解

说明&#xff1a; SAP中的替代有三种&#xff1a; A物料和B物料可以互相替代&#xff0c;但是由物料计划部门自由控制使用A还是使用B;在某个产品中&#xff0c;当物料A不够时&#xff0c;才用B&#xff1b;当物料A用完后&#xff0c;将永远不再用&#xff0c;而是用物料B取代A…

CYEZ 模拟赛 7

A 弹珠 妙妙题。 先每个组分一个小球。等价于 n − k n-k n−k 拆分为任意个 [ 1 , k ] [1,k] [1,k] 的数的方案数。 本质是根据面积的转换&#xff0c;直观解释&#xff1a; 完全背包即可。代码。 B C 总结

机器人制作开源方案 | 家庭清扫拾物机器人

作者&#xff1a;罗诚、李旭洋、胡旭、符粒楷 单位&#xff1a;南昌交通学院 人工智能学院 指导老师&#xff1a;揭吁菡 在家庭中我们有时无法到一些低矮阴暗的地方进行探索&#xff0c;比如茶几下或者床底下&#xff0c;特别是在部分家庭中&#xff0c;如果没有及时对这些阴…

设计加速!11个Adobe XD插件推荐!

你是否一直在寻找可以提升 Adobe XD 工作流程和体验的方法&#xff1f;如果是&#xff0c;一定要试试这些 Adobe XD 插件&#xff01;本文将介绍 11 款好用的 Adobe XD 插件&#xff0c;这些插件可以为 UI/UX 设计添加很酷的新功能&#xff0c;极大提升你的工作效率和产出。让我…

Linux 常用基本命令

1.走近Linux系统 开机登录 开机会启动许多程序。它们在Windows叫做"服务"&#xff08;service&#xff09;&#xff0c;在Linux就叫做"守护进程"&#xff08;daemon&#xff09;。 关机 在linux领域内大多用在服务器上&#xff0c;很少遇到关机的操作。毕竟…