C语言:内存函数

ops/2024/10/20 11:45:55/

再前面我们学习了如何将arr1里的字符串拷贝到arr2里,这时我们创建两个整形数组,如果我们也想将arr3里的元素拷贝到arr4里我们该怎么办呢,当然我们一定是不能用我们前一篇学习的strcpy函数了,因为strcpy的参数类型为char,但我们现在为int,这时我们就要用到我们的内存函数了。

#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = "abcdef";char arr2[20] = {0};strcpy(arr1, arr2);int arr3[] = { 1,2,3,4,5 };int arr4[5] = { 0 };return 0;
}

内存函数

1.memcpy 使用和模拟实现

形式

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

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

 参数1:destination, 类型:char ,表示内存拷贝的目的位置*

参数2:source,类型:char ,表示内存拷贝的起始位置*

参数3:count,类型:size_t,表示拷贝内存字节的个数

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

e49a486976c04a0286378b9d1486598f.png

我们发现利用这个函数我们能将arr1的前五个元素复制到arr2里。当然对于这个函数我们也是可以模拟实现的。

模拟实现

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

对于这个函数的交换其实我们是利用字节进行交换,每循环一次交换一个字节,并且向前移动一个字节,循环条件为交换的字节个数,每交换一次就num--; 

b5eeab8145ad4c108c6a0469a275daf7.png

这时如果我们想要让同一个数组中arr1[10]={0,1,2,3,4,5,6,7,8,9}中让0,1,2,3,4替换2,3,4,5,6.是否可以呢

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

7a5d30cfd38a4e8e84436ec5612b8e77.png

我们发现并没有实现,这是因为当我们将0和1复制到2,3的时候我们已经改变了他们的值,当我们要将第三和第四个数复制 4和5的位置时复制的其实已经是改变了的0和1了,这时同样也改变了4和5.所以对于这些有重叠的我们会将他交给memmove函数来解决。

2.memmove 使用和模拟实现

形式

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

  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。 
#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = { 0,1,2,3,4,5,6,7,8,9 };int arr2[10] = { 0 };memmove(arr1+2, arr1, 5*sizeof(int));int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}return 0;
}

eacf4786cda947d09201a84b320d29e1.png

我们发现,我们成功的解决了重叠的问题,那么我们又到了模拟实现memmove函数的时候了。

模拟实现

dest为目标地址,src为源头。

#include<stdio.h>
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = dest;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 dest;
}
int main()
{int arr1[10] = { 0,1,2,3,4,5,6,7,8,9 };my_memmove(arr1 + 2, arr1, 5 * sizeof(int));for (int i = 0; i < 10; i++){printf("%d ", arr1[i]);}return 0;
}

让我们来分析一下吧,我们发现我们一直再从前向后拷贝,如果我们从后向前拷贝,能否解决呢,我们发现是可以的,但可惜,我们发现如果我们想要拷贝的数是后面的 5,6,7,8,9,如果我们从后向前拷贝还是会改变值,

1d11f8dcaaed42ebb1af46392d5e53de.png

当然这时我们也发现了其实我们可以将两种方式结合。如果目标空间的地址(dest)小于源头(src)我们就可以用从前向后拷贝,如果目标空间的地址(dest)大于源头(src)我们就可以用从后向前拷贝(数组的地址是由低到高,递增的)。

d0c43e106cad4d9081614001d8708b6d.png

首先利用if语句形成从前向后和从后向前的语句,当然我们还是利用字符进行交换,循环条件为num--,从前向后的交换语句就是我们之前memcpy函数的交换语句,从后向前的交换语句,就是找到目标空间和源头的最后一个字符,然他们进行交换,如果交换5个元素就是20个字符,最后一个字符就是(char*)dest+19和(char*)src+19,我们可以发现while循环的条件是

num--;当num=20时,num--就等于19,所以我们就可以吧交换语句写成(char*)dest+num和(char*)src+num,每循环一次num就会改变,交换也会进行。

 

81ed083741a44dac90cab7ed3f703010.png

3.memset 函数的使用

形式

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

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

#include<stdio.h>
#include<string.h>
int main()
{char arr[] = "Hello World";memset(arr, 'x', 5);printf("%s", arr);return 0;
}

a5504bed5f8b4652a35b0f8e6c0f1e8d.png

当然如果我们想要改变的是world也是可以的,只需要我们将arr+6就可以了

#include <stdio.h>
#include <string.h>
int main()
{char arr[] = "hello world";memset(arr+6, 'x', 5);printf(arr);return 0;
}

 

4. memcmp 函数的使用

形式

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

  • 比较从ptr1和ptr2指针指向的位置开始,向后的num个字节 
  • 两个内存中不匹配的第一个字节是ptr1>ptr2时,返回大于0的数
  • 两个内存中不匹配的第一个字节是ptr1<ptr2时,返回小于0的数
  • 如果全部相同返回0
#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = "abcdf";char arr2[] = "abcde";int ret = memcmp(arr1, arr2,5);printf("%d", ret);return 0;
}

17cc802173cb4483a4015308c912c791.png

#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[] = { 1,2,3,5 };//arr1中1的存放形式:01 00 00 00   2的:02 00 00 00  3的:03 00 00 00  4的:04 00 00 00//arr2中1的存放形式:01 00 00 00   2的:02 00 00 00  3的:03 00 00 00  5的:05 00 00 00int ret=memcmp(arr1, arr2, 16);printf("%d", ret);return 0;
}

当然对于他们之间的比较其实就是对应着进行比较当比到最后时发现5大于4就会返回一个负值。

 

好了今天的分享就到这里了,请大家多多关注,我们下一篇见!dangdang,


http://www.ppmy.cn/ops/93876.html

相关文章

git push失败,git操作顺序

git push失败&#xff0c;git操作顺序 ! [rejected] peter -> peter (fetch first) error: 推送一些引用到 ‘http://git…com.cn/zhjg/umc_v2.git’ 失败 提示&#xff1a;更新被拒绝&#xff0c;因为远程仓库包含您本地尚不存在的提交。这通常是因为另外 提示&#xff1a;…

Ruby 文件的输入与输出

Ruby 文件的输入与输出 在编程中,文件的输入与输出(I/O)是一项基本且重要的功能。Ruby 作为一种高级编程语言,提供了简洁而强大的文件 I/O 操作方法。本文将详细介绍 Ruby 中如何进行文件的读取、写入和操作。 1. 文件读取 Ruby 中,文件读取主要通过 File 类和其相关的…

密码输入检测(100%用例)D卷(JavaPythonC++Node.jsC语言)

给定用户密码输入流 input,输入流中字符<表示退格,可以清除前一个输入的字符,请你编写程序,输出最终得到的密码字符,并判断密码是否满足如下的密码安全要求。 密码安全要求如下: 1.密码长度>=8; 2.密码至少需要包含 1 个大写字母; 3.密码至少需要包含 1 个小写字母…

容器化部署ES集群

文章目录 一、ElasticSearch基本概念1、索引(Index)2、文档(Document)3、分片和副本4、映射(Mapping) 二、容器部署ElasticSearch集群三、容器部署ElasticSearch伪集群 一、ElasticSearch基本概念 1、索引(Index) 在ElasticSearch中&#xff0c;索引是文档的集合&#xff0c;类…

[算法2] 第二集 二叉树中的深度搜索

深度优先遍历&#xff08;DFS&#xff0c;全称为 Depth First Traversal&#xff09;&#xff0c;是我们树或者图这样的数据结构中常⽤的 ⼀种遍历算法。这个算法会尽可能深的搜索树或者图的分支&#xff0c;直到⼀条路径上的所有节点都被遍历 完毕&#xff0c;然后再回溯到上…

[ 烧录 ]蓝牙一键烧录调试程序-批量烧写-MAC地址自增-串口调试-Phy62XX-ST17H6X-支持奉加微电子和伦茨科技

目录 一、前言 二、使用痛点 2.1 烧写操作多 2.2 数据交互需要再打开串口助手 2.3 调试信息不支持中文 2.4 批量烧写效率低、MAC地址无法增加 三、蓝牙烧写调试助手 3.1 支持奉加微电子和伦茨科技 3.2 嵌入串口调试助手 3.3 一键烧写 3.4 烧写调试无缝衔接 3.5 支持…

人工智能在病理组学领域的最新进展|文献速递·24-08-09

小罗碎碎念 本期推文主题&#xff1a;人工智能在病理组学领域的最新进展 这一期推文和往期不太一样——往期几乎都是顶刊&#xff0c;而这一期选了一些分数不那么高的文章。这样做有两个原因&#xff1a; 验证一下在IF较低的期刊中能否找到灵感对比一下&#xff0c;期刊之间的…

【AI人工智能】文心智能体 - 你的专属车牌设计师

引言 自AI盛行以来&#xff0c;不断有各种各样的人工智能产品崭露头角。我们逐步跟着不断产生的人工智能来使自己的工作和生活变得更加智能化&#xff01;那么我们是否能够创造一款专属于自己的人工智能产品呢&#xff1f; 文心智能体平台就给我们提供了这样的机会&#xff0c…