当前位置:首页 » 《随便一记》 » 正文

【进阶C语言】内存函数(详解)

1 人参与  2023年04月05日 14:49  分类 : 《随便一记》  评论

点击全文阅读


前言

上一期讲的函数都是和字符串相关的,但是我们在操作数据的时候,不仅仅是操作字符串的数据,还得需要内存函数的应用


内存函数的应用

1. memcpy1.1 memcpy的介绍1.2 memcpy的使用1.3 模拟实现memcpy库函数1.4 我想在1,2后面打印1,2,3,4,5会怎么样? 2. memmove2.1 memmove的介绍2.2 memmove的使用2.3 模拟实现memmove库函数 3. memcmp3.1 memcmp的介绍3.2 memcmp的使用 4. memset4.1 memset的介绍4.2 memset的使用

1. memcpy

1.1 memcpy的介绍

void * memcpy ( void * destination, const void * source, size_t num );
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。这个函数在遇到 ‘\0’ 的时候并不会停下来。如果source和destination有任何的重叠,复制的结果都是未定义的。

1.2 memcpy的使用

用代码举例:

int main(){int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[8] = { 0 };//把arr1中的前5个数据拷贝到arr2中memcpy(arr2, arr1, 20);//strcpy不能用,它只针对字符串拷贝,而上面的是整型数据return 0; }

在这里插入图片描述
试试浮点型看看可不可以:

int main(){float arr1[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };float arr2[8] = { 0 };//把arr1中的前5个数据拷贝到arr2中memcpy(arr2, arr1, 12);return 0; }

在这里插入图片描述

从中发现memcpy它并不在乎整型还是浮点型,所以叫他内存拷贝

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

在分析一下上面的信息:
void* – 通用类型的指针,可以接受任意类型数据的地址,但是这种指针不能直接解引用和加减运算!
memcpy函数的设计者,不知道未来程序员使用memcpy拷贝什么类型的数据!
size_t num 表示拷贝多少个字节

1.3 模拟实现memcpy库函数

//memcpy函数返回的是目标空间的起始地址#include <assert.h>void* my_memcpy(void* dest, const void* src, size_t num){void* ret = dest;assert(dest && src);while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;}int main(){int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[8] = { 0 };//把arr1中的前5个数据拷贝到arr2中my_memcpy(arr2, arr1, 20);return 0; }

调试监视结果如下:

在这里插入图片描述

1.4 我想在1,2后面打印1,2,3,4,5会怎么样?

#include <assert.h>void* my_memcpy(void* dest, const void* src, size_t num){void* ret = dest;assert(dest && src);while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;}int main(){int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };//   你先打印  1 2 1 2 3 4 5 8 9 10//   结果却是  1 2 1 2 1 2 1 8 9 10my_memcpy(arr1 + 2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}}

在这里插入图片描述
红色框框:目标空间
绿色框框:想要拷贝的原数据

结论:
所以我们发现:在内存重叠的时候,使用memcpy可能会出现意想不到的结果
建议在内存重叠的情况,使用memmove函数.

2. memmove

2.1 memmove的介绍

void * memmove ( void * destination, const void * source, size_t num );
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。如果源空间和目标空间出现重叠,就得使用memmove函数处理。

2.2 memmove的使用

int main(){int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };//   你先打印  1 2 1 2 3 4 5 8 9 10//   结果却是  1 2 1 2 3 4 5 8 9 10//说明没有问题memmove(arr1 + 2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}}

代码结果:
在这里插入图片描述

2.3 模拟实现memmove库函数

在这里插入图片描述
红色框框:目标空间
蓝色框框:想要拷贝的原数据
在这里插入图片描述
当dest在src前面,也就是dest的地址更低,src的地址更高的时候
在这里插入图片描述
整个图片概念图:
在这里插入图片描述
从而有两种方案,综合比较,B方案效果更好
在这里插入图片描述
B方案图片解释:
在这里插入图片描述
代码样子:

if (dest < src){//前->后}else{//后->前}

完整版代码:

//memcpy函数返回的是目标空间的起始地址#include <assert.h>void* my_memmove(void* dest, const void* src, size_t num){void* ret = dest;assert(dest && src);if (dest < src){//前->后while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else{//后->前while (num--){*((char*)dest + num) = *((char*)src + num);}}return ret;}int main(){int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };//             1 2 1 2 3 4 5 8 9 10my_memmove(arr1 + 2, arr1, 20);//my_memmove(arr1, arr1+2, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}}

总结:
C语言:memcpy拷贝不重叠的内存
重叠的就交给memmove
memmove > memcpy 100 60
VS:100 100

3. memcmp

3.1 memcmp的介绍

int memcmp ( const void * ptr1,  const void * ptr2,  size_t num );
比较从ptr1和ptr2指针开始的num个字节返回值如下:在这里插入图片描述

3.2 memcmp的使用

int main(){int arr1[] = { 1,2,3,4,5 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00int arr2[] = { 1,2,3,4,6 };//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 06 00 00 00int ret = memcmp(arr1, arr2, 17);printf("%d\n", ret);}

代码结果:
在这里插入图片描述

4. memset

4.1 memset的介绍

void * memset ( void * ptr, int value, size_t num );

将 ptr 指向的内存块的第一个字节数设置为指定值(解释为无符号字符)。

4.2 memset的使用

int main(){char arr[] = "hello world";//以字节为单位来进行设置的memset(arr, 'x', 5);printf("%s\n", arr);}

代码结果:
在这里插入图片描述
注意:memset是以字节为单位来进行设置的!!
什么意思呢?

int main(){int arr[10] = { 0 };//01 01 01 01memset(arr, 1, sizeof(arr));//这种写法无法将数据的每个元素设置为1int i = 0;for (i = 0; i < 10; i++){printf("%x ", arr[i]);}}

体会代码结果:

这种写法无法将数据的每个元素设置为1

在这里插入图片描述

如果这份博客对大家有帮助,希望各位给恒川一个免费的点赞作为鼓励,并评论收藏一下,谢谢大家!!!
制作不易,如果大家有什么疑问或给恒川的意见,欢迎评论区留言。


点击全文阅读


本文链接:http://zhangshiyu.com/post/58474.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1