当前位置: 首页 > news >正文

【C语言】内存函数

内存函数

文章目录

  • 内存函数
  • 1.memcpy的使用和模拟实现
  • 2.memmove的使用和模拟实现
  • 3.memset的使用
  • 4.memcmp的使用和模拟实现


1.memcpy的使用和模拟实现
2.memmove的使用和模拟实现
3.memset的使用
4.memcmp的使用和模拟实现

1.memcpy的使用和模拟实现

在前两篇我们学习了字符串函数和字符函数,那么对于不是字符类型的数据或者不清楚的数据类型,当我们想要对他们进行拷贝,比较时应该怎末办呢?

C语言也为我们提供了内存函数,来处理这些问题。

先介绍memcpy函数

函数声明:

void* memcpy(void* destination,void* source,size_t num);

通过函数声明,可以看得出来他跟strncpy函数十分相似,无非就是适用的数据类型不同而已。

但并非如此

注意:

1.这个函数在遇到’\0’时并不会停下来
2.当destination和source出现重叠时,结果就是未定义的
3.函数memcpy从source的位置开始向后复制num个字节的数据到desitination 指向的内存位置

函数使用

#include<stdio.h>
#include<string.h>
int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };memcpy(arr2, arr1, 5);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}

在这里插入图片描述
那通过调试,就会清楚输出结果为 1 2 0 0 0 0 0 0 0 0

函数的模拟实现

#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memcpy(void* dest,const  void* str, size_t num)
{void* m = dest;assert(dest);assert(str);while (num){*(char*)dest = *(char*)str;dest = (char*)dest + 1;str = (char*)str + 1;num--;}return m;}
//
int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };my_memcpy(arr2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}

2.memmove的使用和模拟实现

在上边memcpy强调了destination与source是不能出现重叠的,那如果出现重叠又要怎样实现呢?

这就不得不请出memmove了

memmove与memcpy的区别就是memmove处理的源内存块和目标内存块可以重叠

函数声明:

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

函数使用

#include<stdio.h>
#include<string.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };memmove(arr + 3, arr, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

在这里插入图片描述
函数模拟实现

分析一波

在这里插入图片描述
在这里插入图片描述
如图所示,dest作为目标空间,str作为源空间

dest与str的关系无非就3种。

第一种就是红色箭头所示,dest>str时,我们就可以把str的数据一个字节一个字节的拷贝给dest,并不会因为拷贝过去的字节覆盖之前的字节而影响效果

第二种就是dest>(char*)str+count,这时候,dest与str已经不再重叠,那就和第一种一样,将字节逐一拷贝过去就可以

第三种str<dest<(char*)str+count,

在这里插入图片描述
如果我们还像第一种那样,按照粉色箭头把str的数据一点点拷贝到destination 中,就会出现一个问题

那就是当我们把第一个数据拷贝过去后,再拷贝第二个数据就会发现原来的第二个数据已经被之前拷贝过去的数据覆盖了

因此可以通过改变开始拷贝的起点来避免这种情况的发生。

将起点改变成(char*)dest+count-1,和(char*)str+count-1,然后反着将str的数据拷贝到dest的空间就可以了

函数模拟实现

void* my_memmove(void* dest, void* str, size_t num)
{void* m = dest;if (dest <= str || (char*)dest >= ((char*)str + num)){while (num){*(char*)dest = *(char*)str;dest = (char*)dest + 1;str = (char*)str + 1;num--;}}else{dest = (char*)dest + num - 1;str = (char*)str + num - 1;while (num){*(char*)dest = *(char*)str;dest = (char*)dest - 1;str = (char*)str - 1;num--;}}return m;}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr + 2, arr, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

在这里插入图片描述

3.memset的使用

memset是用来设置内存的,将内存中的值以字节为单位设置成想要的内容

函数声明:

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

函数使用

int main()
{char s[20] = "hello world";memset(s, 'w', 5);printf("%s\n", s);//输出wwwww worldreturn 0;
}

但是这个字符常量不能是一个字符串
在这里插入图片描述

4.memcmp的使用和模拟实现

函数声明:

int memcmp(const void* str1,const void* str2,size_t num);

比较从str1和str2指针指向的位置开始,向后的num个字节

返回值:
在这里插入图片描述
函数使用:

int main()
{char s[20] = "hello world";char m[20] = "hello worid";int ret = memcmp(s, m, 11);printf("%d\n", ret);
}

函数模拟实现

int my_memcmp(void* ptr1, void* ptr2, size_t num)
{int count = 0;while (*(char*)ptr1 == *(char*)ptr2){ptr1 = (char*)ptr1 + 1;ptr2 = (char*)ptr2 + 1;count ++ ;if (count == num)return 0;}return *(char*)ptr1 - *(char*)ptr2;
}
int main()
{char s[20] = "hello world";char m[20] = "hello worid";int ret=my_memcmp(s, m, 5);printf("%d\n", ret);return 0;
}

内存函数和字符串函数基本大同小异,因此学起来也比较容易,只要多加练习能熟练掌握在日常写代码的过程中就可以了

作者有话说:作者只是一只小白,以上均是在学习完后对知识的理解,如有错误和不足,感谢指出;若觉得有帮助,可以留下一个👍,一起加油!


http://www.mrgr.cn/news/8407.html

相关文章:

  • 如何使用ssm实现基于HTML5的出租车管理系统
  • NLP位置编码
  • 基于Springboot2 + vue3酒店客房预订管理系统
  • rust 日志记录与跟踪
  • 游戏开发设计模式之责任链模式
  • Gameplay Ability System(通过表配置不同等级的伤害)
  • Ruby跨平台移动应用开发的新篇章
  • 国货之光|暴雨机推出面向大模型训练的AI服务器
  • 【Node】【2】创建node应用
  • 汇编语句中的 jmp 与 call 指令
  • 微服务事务管理
  • GATK AlleleList接口介绍
  • 鸿蒙学习(四):泛型空安全模块导入导出
  • 分享从零开始学习网络设备配置--任务6.2 实现网络设备的远程管理
  • C语言 | Leetcode C语言题解之第355题设计推特
  • 后端完成api顺序
  • RK3588——网口实时传输视频
  • [Algorithm][综合训练][求最小公倍数][跳台阶][最长回文子串]详细讲解
  • 【机器学习】实验设计之一次一因子方法(OFAT)、全因子设计方法(FFD)响应面方法(RSM)和插值方法以及如何选择控制因子的概念
  • 【Java】/* 单向链表 - 底层实现 */