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

目录

         一,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 < curif (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;
}

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

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

相关文章

Shell环境变量深入:自定义系统环境变量

Shell环境变量深入&#xff1a;自定义系统环境变量 目标 能够自定义系统级环境变量 全局配置文件/etc/profile应用场景 当前用户进入Shell环境初始化的时候会加载全局配置文件/etc/profile里面的环境变量, 供给所有Shell程序使用 以后只要是所有Shell程序或命令使用的变量…

H.机房【蓝桥杯】/数组链式前向星建图+堆优化版dijkstra

机房 数组链式前向星建图堆优化版dijkstra #include<iostream> #include<queue> #include<cstring> #include<vector> using namespace std; typedef pair<int,int> pii; //无向图开两倍 int e[200005],ne[200005],v[200005],h[200005],du[1000…

STL---unordered set和unordered multiset【无序集合】

1.1 定义及初始化&#x1f357; 下面列出常用的初始化方式 #include <unordered_set> #include <iostream> using namespace std; //输出s中的所有元素 template<typename T> void Show(const T& s) {for (auto& x : s) …

Python的pip配置、程序运行、生成exe文件

一、安装Python 通过官网下载对应的版本&#xff0c;安装即可。 下载地址&#xff1a;Download Python | Python.org Python标准库查看&#xff08;Python自带库&#xff09; Python 标准库文档 安装Python的时候&#xff0c;如果选第二个自定义安装要记得勾选安装pip 二、…

2024/05/25学习记录

1、面经复习&#xff1a;前端广度 2、代码随想录刷题&#xff1a;动态规划 3、rosebush 完成input组件基础

闲置商标转让出现这些状态时注意!

近日以前做转让的一个朋友的商标转让证明下来&#xff0c;正好是2个半月&#xff0c;普推知产老杨发现这个时间也太快&#xff0c;以前差不多四个月左右&#xff0c;有些朋友需要购买闲置商标&#xff0c;3个月内所有权就变成自己的。 在购买闲置商标时要注意有一些细节&#x…

MySQL的索引, 到底怎么创建?

目录 前言 MySQL的数据结构 索引是一把双刃剑 索引创建原则 如何给一个列挑选索引? 索引列的基数, 要尽量小 索引列的类型尽量小 索引长字符串的前缀 不要对索引列进行计算操作或者函数计算. 不要老想着查询, 想想插入该怎么办? 避免索引冗余和重复 前言 今天在…

TOTP 算法实现:双因素认证的基石(C/C++代码实现)

双因素认证&#xff08;Two-Factor Authentication, 2FA&#xff09;扮演着至关重要的角色。它像是一道额外的防线&#xff0c;确保即便密码被窃取&#xff0c;不法分子也难以轻易突破。在众多双因素认证技术中&#xff0c;基于时间的一次性密码&#xff08;Time-Based One-Tim…

【fastapi+mongodb】使用motor操作mongodb

上一篇文章&#xff0c;我们在电脑上安装了mongodb数据库。这篇文章&#xff0c;我们在fastapi后端使用motor操作mongodb 如果你还没看过上一篇文章&#xff0c;链接在这里&#xff1a;【MongoDB】安装与使用 安装 motor motor 是一个用于操作 mongodb 数据库的 python 库&a…

计算机网络 1

两台主机想通信&#xff0c;其实本质就是两个文件的资源交换&#xff0c;但是长距离的通信&#xff0c;面临的是很多的问题。这个时候需要通过一些方式来保证可靠性 什么是协议 这样一个例子&#xff0c;我是住在农村&#xff0c;我读高中了我需要去县里面读书。这个时候呢&…

Jupyter Lab 软件安装与使用

软件简介 Jupyter Lab 软件是一个基于web 的交互式开发环境&#xff0c;集成了代码编辑器、终端、文件管理器等功能&#xff0c;使得开发者可以在一个界面中完成各种任务。JupyterLab是Jupyter Notebook的全面升级&#xff0c;是一个集文本编辑器、终端以及各种个性化组件于一…

Java进阶学习笔记29——Math、System、Runtime

Math&#xff1a; 代表的是数学&#xff0c;是一个工具类&#xff0c;里面提供的都是对数据进行操作的一些静态方法。 示例代码&#xff1a; package cn.ensourced1_math;public class MathTest {public static void main(String[] args) {// 目标&#xff1a;了解Math类提供…

那智不二越机器人维修案例分享

那智不二越工业机器人在工业范围内广泛应用于各种生产领域。其示教器作为人机交互的重要设备&#xff0c;常常需要定期维护和Nachi不二越机械手示教盒修理。 【Nachi不二越机器人示教器维修步骤】 1. 关闭电源 在进行任何那智不二越机器人维修操作之前&#xff0c;务必确保机器…

<商务世界>《75 微课堂<茶叶(1)-质量分级>》

1 中国茶叶分级 中国的10级标准是按照茶叶的外观、香气、滋味、汤色、叶底五个方面进行评分&#xff0c;分别用10分制进行评分&#xff0c;总分为50分&#xff0c;得分越高&#xff0c;茶叶的品质就越高。具体的分数和等级如下表所示&#xff1a; 2 每级的特点 茶叶的质量等级…

OceanBase SQL 诊断和调优实践——【DBA从入门到实践】第七期

数据库作为绝大多数应用系统储存数据的核心系统&#xff0c;在用户系统需要访问数据时&#xff0c;有着至关重要的作用。在这些交互中&#xff0c;SQL 语言是应用与数据库系统之间“沟通”的桥梁&#xff0c;它负责将应用的指令传达给数据库。因此&#xff0c;SQL 的性能好坏直…

弱类型解析

php中 转化为相同类型后比较 先判断数据类型后比较数值 var_dump("asdf"0);#bool(true) var_dump("asdf"1);#bool(false) var_dump("0asdf"0);#bool(true) var_dump("1asdf"1);#bool(true)1、md5撞库 例&#xff1a; <?php incl…

【智能算法应用】模拟退火算法求解多车型车辆路径问题HFVRP

目录 1.算法原理2.多车型车辆路径HFVRP数学模型3.结果展示4.参考文献5.代码获取 1.算法原理 模拟退火算法&#xff08;Simulated Annealing, SA&#xff09;是一种通用概率算法&#xff0c;用于在给定一个大的搜索空间内寻找问题的近似最优解。这种算法受到物理中退火过程的启…

烟囱ERP系统

一、烟囱系统定义 “烟囱式”系统&#xff0c;来自维基百科的解释是&#xff1a;一种不能与其他系统进行有效协调工作的信息系统&#xff0c;又称为孤岛系统。 二、烟囱系统的案例 比如&#xff1a;就像以下一样&#xff0c;各个系统之间是独立的&#xff0c;所有对接是通过…

深度学习复盘与小实现

文章目录 一、查漏补缺复盘1、python中zip()用法2、Tensor和tensor的区别3、计算图中的迭代取数4、nn.Modlue及nn.Linear 源码理解5、知识杂项思考列表6、KL散度初步理解 二、处理多维特征的输入1、逻辑回归模型流程2、Mini-Batch (N samples) 三、加载数据集1、Python 魔法方法…

c++笔记3

优先队列 普通的队列是一种先进先出的数据结构&#xff0c;元素在队列尾追加&#xff0c;而从队列头删除。优先队列是一种按照优先级决定出队顺序的数据结构&#xff0c;优先队列中的每个元素被赋予级别&#xff0c;队首元素的优先级最高。 例如&#xff1a;4入队&#xff0c…