内存函数详解,包含部分字符串函数

目录

         一,memcpy内存函数的介绍

二memmove函数的介绍

三,memset的函数使用

四,memcmp的介绍

五,内存函数的模拟实现,以及一个字符串函数strstr的模拟实现

        5.1memcpy函数的实现

        5.2memmove的模拟实现

        5.3memcmp的模拟实现

        5.4 strstrg函数的模拟实现(暴力实现以及KMP算法实现)


内存操作函数

memcpy的使用以及模拟实现

memmove的使用以及模拟实现

memcmp的使用以及模拟实现

memset的使用

strstr的模拟实现

一,memcpy内存函数的介绍

void* memcpy(void* destination, const void* source, size_t num);
这里我们可以看到,他是有三个参数的,其中有俩个无符号指针,还有一个是无符号的num
这俩个指针,一个指向目标要改变的数据的地址,另一个是源地址,要拷贝到我们目标中
当然这里使用无符号类型的指针,是为了我们能拷贝任何类型的数据,就不仅限于拷贝字符

解释如下

函数 memcpy source 的位置开始向后复制 num 个字节的数据到 destination 的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来,因为我们给了需要拷贝的字节大小,所以拷贝停止是由我们自己来控制的
如果 source destination 有任何的重叠,复制的结果都是未定义的。
这个意思是所不能在自己的后面拷贝自己,因为可能会导致越界的风险,当然在VS下是可以自己拷贝自己的内容的,但是在不同的编译器中,可能效果不同,有些编译器是不允许这样使用的

这便是在自己后面进行拷贝,然后出现越界的情况,例如在字符串中,他在拷贝的过程中,可以会将'\0'修改,导致字符串没有结尾标志。

可以看到,我们将arr2中的数据拷贝到了arr1中去,而arr1和arr2中存放的都是int类型的变量,这就是和字符串拷贝的区别,当然我们也可以拷贝其他类型的变量,例如结构体

memmove函数的介绍

void* memmove(void* destination, const void* source, size_t num);

这里我们可以看到,他是有三个参数的,其中有俩个无符号指针,还有一个是无符号的num
这俩个指针,一个指向目标要改变的数据的地址,另一个是源地址,要拷贝到我们目标中
当然这里使用无符号类型的指针,是为了我们能拷贝任何类型的数据,就不仅限于拷贝字符
memcpy 的差别就是 memmove 函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用 memmove 函数处理。
当然他也能在字符串后面去追加自己的部分
我们可以看到,他是能在他自己的后面追加内容的。

三,memset的函数使用

void *memset( void *dest, int c, size_t count );

memset函数,有三个参数,一个是无符号的指针,一个是你要设置的符号是什么,最后一个参数是无符号的整形,返回类型是无符号的指针类型,指向的是 *dest的首元素地址

memset函数的功能是,在dest里面设置count字节的符号C,并返回dest的地址

我们使用memset就能使我们想要的字节个数的内容变成我们需要的值。

四,memcmp的介绍

int memcmp(const void* ptr1, const void* ptr2, size_t num);

我们可以看到,他有三个参数,前俩个是我们要比较内容的地址,最后一个是我们要比较的个数,返回类型是int类型,如果ptr1 > ptr2 则返回 > 0 的数,如果ptr1 < ptr2 则返回 0  < 的数,如果 ptr1 == ptr2 则返回 0

五,内存函数的模拟实现,以及一个字符串函数strstr的模拟实现

5.1memcpy函数的实现

void* my_memcpy(void* dest, const void* cur, size_t num)
{
	//保留dest的地址
	void* ret = dest;
	while (num)
	{
		*(char*)dest = *(char*)cur;
		dest = (char*)dest + 1;
		cur = (char*)cur + 1;
		num--;
	}
	//返回dest的地址
	return ret;
}
int main()
{

	char str1[] = "hello world .............";
	char str2[] = ".............";
    //将str2的前5个字节的内容拷贝到str1中
	my_memcpy(str1,str2,5sizeof(str2[0]));
	
	printf(str1);

	return 0;
}

5.2memmove的模拟实现

图,一

图,二

当然在拷贝自己时会出现上述俩种情况,如果我们一直只选一直拷贝方式,例如,从前向后拷贝因为cur和dest都是来自同一部分,那么会出现什么情况呢,我们在dest > cur时,在拷贝的时候就已经将存储在a ,b ,c 之后的数据d,e,f修改为 a,b,c 因为dest和cur指向的是同一块内容,那么cur里面的数据 d,e,f也被修改了,那么就达不到我们需要的拷贝效果。这时我们就要进行一定的判断,当dest > cur时,我们从后向前拷贝,当 cur > dest时我们从前向后拷贝。当然,如果不是相同地址块的内容,如何拷贝不会影响他们的结果,这个判断只对拷贝同一块地址内容进行区分。

代码如下

void* my_memmove(void* dest, const void* cur, size_t num)
{
	void* ret = dest;
	//为了防止自己拷贝自己导致的内容覆盖
    //如果dest < cur
	if (dest < cur)
	{
		while (num)
		{
			*(char*)dest = *(char*)cur;
			dest = (char*)dest + 1;
			cur = (char*)cur + 1;
			num--;
		}
	}
	else
	{
		dest = (char*)dest + num;
		cur = (char*)cur + num;
		while (num)
		{
			*(char*)dest = *(char*)cur;
			dest = (char*)dest - 1;
			cur = (char*)cur - 1;
			num--;
		}
	}
}
int main()
{

	char str1[] = "hello world .............";
	char str2[] = ".............";
	my_memmove(str1,str1+5,6);
	
	printf(str1);

	return 0;
}

5.3memcmp的模拟实现

int my_memcmp(void* pstr1, char* pstr2, size_t num)
{

	while (num)
	{
		//如果某个字节的值不相等,则中断循环
		if (*(char*)pstr1 != *(char*)pstr2)
		{
			break;
		}
		//相等这继续向下走
		pstr1 = (char*)pstr1 + 1;
		pstr2 = (char*)pstr2 + 1;
		num--;
	}
	//直接返回pstr1 和 pstr2对应的差值即可
	return (*(char*)pstr1 - *(char*)pstr2);
}

int main()
{

	char str1[] = "hello world .............";
	char str2[] = "hello word";
	int ret = my_memcmp(str1,str2,5);
	
	printf("ret = %d",ret);

	return 0;
}

可以看到,直接返回了不相等部分的差值,大于0 说明前num个字节 str1大于str2

可以看到,直接返回了相等部分的差值,等于0 说明前num个字节 str1等于str2

5.4 strstrg函数的模拟实现(暴力实现以及KMP算法实现)

暴力实现:

char* my_strstr(const char* ps1, const char* ps2)
{
	char* p1 = ps1;
	char* p2 = ps2;
	char* p3 = ps1;

	while (*p3 != '\0')
	{
		//每次循环一次,将p3指向的下一个内容给p1,p2回到子集的起点
		p1 = p3;
		p2 = ps2;
		while (*p2 != '\0')
		{
			if (*p2 == *p1)
			{
				//相等就p1和p2向后走,一直比较到 p2指向'\0'为止
				p2++;
				p1++;
			}
			else
			{
				//如果在p2到'\0'之前不相等,这直接跳出循环
				break;
			}
		}
		//如果*p2 == '\0' 那么说明以及在ps1中的子集里找到了与ps2相等的部分,那么就可以返回p3所指向的内容,
		if (*p2 == '\0')
		{
			return p3;
		}
		//如果不相等,p3向后走一位
		p3++;
	}
	//如果一直到最后都没有找到那么将返回空
	return NULL;
}

int main()
{

	char str1[] = "abcdeffghjkln";
	char str2[] = "ffg";

	char* ret = my_strstr(str1,str2);

	printf(ret);

	return 0;
}

KMP算法:
next数组:
由上图next数组我们可以知道
如果我们只知道i之前的next数组下标,那么他之后的应该按照 next[i+1] = k+1,去计算
而图中我们要求的是 i 位置的next数据,那么如果字符串第 i - 1 位置的字符与 k 位置的字符相等,那么next[i] 位置的值就等于 next [i] = next[i-1] + 1,当然,如果 i 的前一个位置的字符串不等于 k 位置的字符串,那么next数组回退到 k 指向的位置,如果一直不相等,直到 k 会退到 -1位置处,在出现进行比较
void GetNext(char* ps2,int* next,int len2)
{
	next[0] = -1;
	next[1] = 0;
	
	int i = 2;
	int k = 0;
    //一直插入数据到next的最后一个位置
	while(i < len2)
	{
        // 如果 k 等于 -1 那么说明已经回退到原点,或者 第 i 的前一项与k位置的字符相等 
		if (k == -1 ||ps2[i - 1] == ps2[k])
		{
			next[i] = k + 1;
			i++;
			k++;
		}
        //不相等这 k 回退到next[k]对应的值
		else
		{
			k = next[k];
		}
	}
}
char* KMP( char* ps1,  char* ps2,int pos)
{
	int len1 = strlen(ps1);
	int len2 = strlen(ps2);
    //我们要找的子串,和需要的主串不能为空
	if (len1 == 0 || len2 == 0)
	{
		return NULL;
	}
    //我们希望开始比较的位置不能大于主串的长度,也不能小于零
	if (pos<0 || pos > len1)
	{
		return NULL;
	}
    //数组这里我们选择动态开辟在堆上建next数组
	int* next = (int*)malloc(sizeof(int) * len2);
    //如果malloc失败这直接返回
	if (next == NULL)
	{
		return;
	}
    //函数得到我们的next数组
	GetNext(ps2, next,len2);
	int i = pos;//遍历主串
	int j = 0;//遍历子串
    //在主串中寻找子串
	while (i < len1 && j < len2)
	{
        //如果 j = -1;这说明需要比较下一个,相等这比较下一个
		if (j == -1||ps1[i] == ps2[j])
		{
			i++;
			j++;
		}
        //不相等将 j 更新为next[k] 对应的值在重新去比较
		else
		{
			j = next[j];
		}
	}
    //释放我们在堆上申请的空间
    free(next);
    // 如果j >= len2的长度则说明已经找到主串中的子串,返回对应位置的地址
	if (j >= len2)
	{
		
		return &ps1[i - j];
	}
	//没有找到返回空
	return NULL;
}

KMP整体代码如下

#include<stdio.h>
#include<stdlib.h>
void GetNext(char* ps2,int* next,int len2)
{
	next[0] = -1;
	next[1] = 0;
	
	int i = 2;
	int k = 0;
	while(i < len2)
	{
		if (k == -1 ||ps2[i - 1] == ps2[k])
		{
			next[i] = k + 1;
			i++;
			k++;
		}
		else
		{
			k = next[k];
		}
	}
}
char* KMP( char* ps1,  char* ps2,int pos)
{
	int len1 = strlen(ps1);
	int len2 = strlen(ps2);
	if (len1 == 0 || len2 == 0)
	{
		return NULL;
	}
	if (pos<0 || pos > len1)
	{
		return NULL;
	}
	int* next = (int*)malloc(sizeof(int) * len2);
	if (next == NULL)
	{
		return;
	}
	GetNext(ps2, next,len2);
	int i = pos;//遍历主串
	int j = 0;//遍历子串
	while (i < len1 && j < len2)
	{
		if (j == -1||ps1[i] == ps2[j])
		{
			i++;
			j++;
		}
		else
		{
			j = next[j];
		}
	}
	if (j >= len2)
	{
		free(next);
		return &ps1[i - j];
	}
	free(next);
	return NULL;
}

int main()
{

	char str1[] = "abcdeffghjkln";
	char str2[] = "ffghjk";

	char* ret = KMP(str1,str2,0);

	printf(ret);

	return 0;
}

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

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

相关文章

自定义原生小程序顶部及获取胶囊信息

需求&#xff1a;我需要将某个文字或者按钮放置在小程序顶部位置 思路&#xff1a;根据获取到的顶部信息来定义我需要放的这个元素样式 * 这里我是定义某个指定页面 json&#xff1a;给指定页面的json中添加自定义设置 "navigationStyle": "custom" JS&am…

计算机毕业设计 | springboot+vue房屋租赁管理系统(附源码)

1&#xff0c;绪论 1.1 课题来源 随着社会的不断发展以及大家生活水平的提高&#xff0c;越来越多的年轻人选择在大城市发展。在大城市发展就意味着要在外面有一处安身的地方。在租房的过程中&#xff0c;大家也面临着各种各样的问题&#xff0c;比如需要费时费力去现场看房&…

模型蒸馏笔记

文章目录 一、什么是模型蒸馏二、如何蒸馏三、实践四、参考文献 一、什么是模型蒸馏 Hinton在NIPS2014提出了知识蒸馏&#xff08;Knowledge Distillation&#xff09;的概念&#xff0c;旨在把一个大模型或者多个模型ensemble学到的知识迁移到另一个轻量级单模型上&#xff0…

【数据结构】二叉树的认识与实现

目录 二叉树的概念&#xff1a; 二叉树的应用与实现&#xff1a; 二叉树实现接口&#xff1a; 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树 二叉树节点个数​编辑 二叉树叶子节点个数 二叉树第k层节点个数 二叉树查找值为x的节点​编辑 二叉树前序遍…

CCF20231201——仓库规划

CCF20231201——仓库规划 代码如下&#xff1a; #include<bits/stdc.h> using namespace std; int main() {int n,m,a[1001][11],b[1001]{0};cin>>n>>m;for(int i1;i<n;i){for(int j1;j<m;j)cin>>a[i][j];}for(int i1;i<n;i){bool foundfals…

分享免费的手机清理软件app,一款国外开发的手机清理神器,让手机再战两年!

手机内存越来越大&#xff0c;软件却越来越占地方&#xff0c;就像微信这家伙&#xff0c;轻轻松松就吃了十几个G&#xff01; 害得阿星8128G的手机&#xff0c;本来想换新的&#xff0c;结果用了这款Avast Cleanup软件&#xff0c;瞬间感觉手机还能再战两年&#xff01; 注意…

2024年云南特岗教师报名流程,超详细,明天就开始报名哦!

2024年云南特岗教师报名流程&#xff0c;超详细&#xff0c;明天就开始报名哦&#xff01;

贪心-leetcode402.移掉 K 位数字-XMUOJ符文序列

题目 思路 话不多说&#xff0c;直接上代码 代码 /*leetcode402.移掉 K 位数字-XMUOJ符文序列--JinlongW-2024/05/26单调栈贪心*/ #include<bits/stdc.h> const int N1010; char num[N],result[N],numStack[N]; int k; using namespace std;void removeKdigits( int k…

[Android]下拉刷新和上拉加载更多

示意图&#xff1a; 1.添加依赖 SwipeRefreshLayout 是一个支持下拉刷新功能的布局&#xff0c;它是 Android Support Library 或 AndroidX 库的一部分。 BaseQuickAdapter 是一个来自开源库 BRVAH (Base RecyclerView Adapter Helper) 的功能丰富的适配器&#xff0c;用于简化…

基于机器学习的一线城市租房价格预测分析与实现,实现三种算法预测

本文旨在基于机器学习方法&#xff0c;对一线城市租房价格进行预测分析&#xff0c;并使用Matplotlib可视化、随机森林、一元线性回归和多元线性模型进行模型对比。通过爬取北京链家二手房数据作为研究对象&#xff0c;探讨了租房价格与各种因素之间的关系&#xff0c;阐述了研…

【数据库基础-mysql详解之索引的魅力(N叉树)】

索引的魅力目录 &#x1f308;索引的概念&#x1f308;使用场景&#x1f308;索引的使用&#x1f31e;&#x1f31e;&#x1f31e;查看MySQL中的默认索引&#x1f31e;&#x1f31e;&#x1f31e;创建索引&#x1f31e;&#x1f31e;&#x1f31e;删除索引 站在索引背后的那个男…

Java时间类--JDK7

一、Date类 1.引言 全世界的时间&#xff0c;有一个统计的计算标准。 1884年&#xff0c;将英国格林威治时间认为是世界标准时间。 在2012年1月份后&#xff0c;由于误差太大&#xff0c;最高可达16min。 取消使用了近130年的格林威治时间&#xff0c;改用原子钟作为世界标…

Mistral AI 团队发布 Mistral-7B-Instruct-v0.3

抱抱脸上线了 Mistral-7B-v0.3 的基础版和指令微调版。 相比于Mistral-7B-v0.2&#xff0c;新版本更新如下&#xff1a; – 词汇量从 32000 扩展到 32768 – 支持 v3 分词器 – 支持函数调用 Mistral-7B-v0.3&#xff1a;网页链接 Mistral-7B-Instruct-v0.3&#xff1a;网页…

vue项目打包教程

如果是用 vue-cli 创建的项目&#xff0c;则项目目录中没有 config 文件夹&#xff0c;所以我们需要自建一个配置文件&#xff1b;在vue项目目录下创建文件 vue.config.js&#xff0c;需注意文件名称必须是 vue.config.js&#xff0c;然后在文件中插入以下代码&#xff1a; 文件…

Wireshark 搜不到字符串?

一个原因是pcap里没有这个字符串&#xff0c; 另一个原因可能是ctrlF之后&#xff0c;选择搜索的地方不对&#xff0c;或者是编码方式选择的不对。 上面图片的第一个下拉框是要搜索的一个范围&#xff0c;是在哪一个panel搜索&#xff0c;范围说明在下面这个链接有详细说明&…

数据结构:树(3)【二叉树链式结构实现】【二叉树的前序,中序,后序遍历】【求二叉树全部结点个数】【求二叉树叶子结点个数】【求二叉树的深度】【单值二叉树】

一.二叉树链式结构的实现 二叉树的链式结构的实现相对于顺序结构的实现就没有那么多的讲究了。就是普通的链表&#xff0c;只不过多了一个指向的指针。 具体结构如下&#xff1a; typedef int BTDataType; typedef struct BinaryTreeNode {BTDataType data;struct BinaryTre…

ASP+ACCESS客户管理信息系统

摘要 本文介绍了客户管理系统的实现方法。目的在于让大家共享学习和运用这一语言的体会和收获。本系统是Internet/Intranet环境下面向电子商务的客户管理&#xff0c;通过企业管理技术、电子商务和信息技术的高度集成&#xff0c;讨论了客户管理系统的系统构架、系统的工作…

深入理解python列表与字典:数据结构的选择与性能差异

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、列表与字典&#xff1a;基础数据结构的对比 二、列表&#xff1a;逐个遍历的查找方式 …

面试题·栈和队列的相互实现·详解

A. 用队列实现栈 用队列实现栈 实现代码如下 看着是队列&#xff0c;其实实际实现更接近数组模拟 typedef struct {int* queue1; // 第一个队列int* queue2; // 第二个队列int size; // 栈的大小int front1, rear1, front2, rear2; // 两个队列的首尾指针 } MyS…

生成式AI导论2024-李宏毅

生成式AI导论2024-李宏毅 第0讲&#xff1a; 课程说明第1讲&#xff1a;生成式AI是什么第2講&#xff1a;今日的生成式人工智慧厲害在哪裡&#xff1f;從「工具」變為「工具人」 第0讲&#xff1a; 课程说明 生成式AI的入门课程 第1讲&#xff1a;生成式AI是什么 生成式人…