【C语言】内存函数

打印 上一主题 下一主题

主题 1740|帖子 1740|积分 5230

大家好,很高兴又和大家见面了!!!
在C语言标准库中,有一些直接对内存进行操纵的函数,我们将其称之为内存函数,这些函数位于头文件<string.h>,在网站https://cplusplus.com/reference/cstring/https://cplusplus.com/https://cplusplus.com/reference/cstring/中我们可以看到这些函数:(ps:这个链接是C语言官网,大家可以打开看一下,非常的详细,包括函数原型等等)

一·必备头文件

所有内存操纵函数都声明在<string.h>头文件中,使用前请确保包罗:
  1. #include <string.h>
复制代码
二·五大内存操纵函数详解 

1. memcpy - 内存复制专家

1.1函数原型

  1. void* memcpy(void* dest, const void* src, size_t n);
复制代码
1.2功能:将src指向的地址开始的n个字节,原样复制到dest指向的地址。



  • 函数有三个参数:第一个参数为拷贝的目的地地址,第二个参数为拷贝的源对象的地址,第三个参数为拷贝的大小,单元为字节。
  • 在拷贝的过程中,函数不会受终止符的影响,只会根据字节数量n来进行拷贝;
  • 在拷贝前必要注意,目的地的空间大小和源对象的空间大小都应该至少是n个字节,而且拷贝的目标空间与源空间不能有重叠。
这里提出一个问题,如下:

遇到如下的代码,如何将arr1中的代码拷贝的arr2中?
  1. #include <stdio.h>#include <string.h>int main(){        int arr1[] = { 1,2,3,4,5,6 };        int arr2[10] = { 0 };}
复制代码
1.3 可以思量运用下标的方法来进行拷贝,如下:

先将arr1中的值赋给arr2,在进行打印。
  1. #include <stdio.h>#include <string.h>int main(){        int arr1[] = { 1,2,3,4,5,6 };        //             0 1 2 3 4 5        int arr2[10] = { 0 };        for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)        {                arr2[i] = arr1[i];        }                for (int i = 0;i < 6;i++)        {                printf("%d ", arr2[i]);        }        return 0;}
复制代码
 

1.4 strcpy函数

这时大概就有同学想到strcpy函数来进行拷贝了,nonononono!!!!
strcpy函数是字符函数,只能用来处理惩罚字符,字符串,这里是数组,所以不可以的。
 1.5memcpy函数

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

 1.6 memcpy的模仿实现

从memcpy的函数原型可知,其返回类型为无返回指针型,所以我们直接按照函数的原型来实现memcpy,这里我们将自己实现的memcpy命名为my_memcpy。
  1. void* my_memcpy(void* dest, const void* src, size_t num)
  2. {
  3.   while (num--)
  4. {
  5.    *(char*)dest = *(char*)src;  //进行拷贝
  6.     //移动指针
  7.         dest = (char*)dest + 1;
  8.         src = (char*)src + 1;
  9. }
  10. }
复制代码
这里大家是否觉得自界说函数已经完成了呢?是否有疑问呢?
比如 dest = (char*)dest + 1; 为什莫不写成++的情势?
为什莫要强制转化成char*的情势?
如果有这样疑问的朋友,那你就忘记指针中的一个紧张知识点了,void*类型的指针不能进行+-整数的运算。因此我们如果要一个字节一个字节的移动地址,那此时就必要将void*的指针强转成char*的指针之后再对其进行+-整数的操纵。
那这个函数完成了嘛,实践出结果! 请看!!

只管运行结果的精确的,但这个是由于我使用的是VS2020版本,强行的运行的结果,所以这个函数还是不完整的,根据提示我们短缺一个返回值(对于void类型的函数而言,它和void类型还是有区别的,void函数不必要返回值,但是void类型的函数是必要返回值的。) 
那返回值是什么呢?
从memcpy函数先容中我们不难发现,在memcpy中,函数的返回值是目标空间地址,所以在我们模仿实现的my_memcpy函数中同样可以将目标空间地址返回。为了确保返回的是目标空间的实在地址,我们可以在开始拷贝前,先将目标空间的起始地址记载下来,最后在拷贝结束后将起始地址返回给函数。修改后的如下
  1. #include <stdio.h>#include <string.h>#include <assert.h>void* my_memcpy(void* dest, const void* src, size_t num){        assert(dest && src);        void* ret = dest;        while (num--)        {                *(char*)dest = *(char*)src;  //进行拷贝                //移动指针                dest = (char*)dest + 1;                src = (char*)src + 1;        }        return ret;}
复制代码
 

1.7 my_memcpy与memcpy的区别

在memcpy函数中,C语言规定它是无法对函数重叠部门进行拷贝的,在我们实现的my_memcpy中可以很好的印证这一点,当有空间重叠的情况存在时,my_memcpy在拷贝时输出的结果会出错,但是在我们在VS中测试memcpy对空间重叠的拷贝时,却能正常拷贝,这阐明VS的功能强大。但是在其他的编译器中不愿定可以实现了。
如下:
  1. #include <stdio.h>#include <string.h>#include <assert.h>void* my_memcpy(void* dest, void* src, size_t n){        assert(dest && src);        void* ret = dest;        while (n--)        {                *(char*)dest = *(char*)src;                dest = (char*)dest + 1;                src = (char*)src + 1;        }        return ret;}int main(){        int arr[] = { 1,2,3,4,5,6,7,8,9,10 };        //     目标:  1 2 1 2 3 4 5 8 9 10        // 这里想将12345拷贝到34567        my_memcpy(arr + 2, arr, 20);        for (int i = 0;i < 10;i++)        {                printf("%d ", arr[i]);        }        return 0;}
复制代码
 

 

所以  memcpy只负责拷贝空间无重叠的情况。 
当空间出现重叠时的拷贝则必要调用我们接下来的函数——memmove 内存移动函数
2.memmove - 安全搬运工

2.1函数原型

  1. void* memmove(void* dest, const void* src, size_t n);
复制代码
与memcpy的区别是memmove处理惩罚的源内存块和目标存快内存可以重叠 。
从memmove函数中我们不难发现,它与memcpy的功能是一样的,只不过相较于memcpy,memmove可以实现重叠部门的拷贝。函数的使用我就不再过多赘述,与memcpy雷同。接下来我们就来重点先容一下如何实现memmove这个函数。
2.2 memmove的模仿实现


 当来源代码在前时,目标空间在后时,重叠空间为源空间的后侧与目标空间的前侧;

当目标空间在后,源空间在前时,重叠空间则为源空间的前侧与目标空间的后侧。 
 因此我们如果想要在拷贝时不会改变重叠空间的内容,那我们只能先处理惩罚重叠空间的内容,再来处理惩罚不重叠空间的内容,因此拷贝的方式就有两种情况:
  1. void* my_memmove(void* dest, void* src, size_t num)
  2. {
  3.         assert(dest && src);
  4.         void* ret = dest;
  5.         if (dest > src)
  6.         {
  7.                 //当源空间在前,重叠空间在后,从后往前拷贝
  8.                 while (num--)
  9.                 {
  10.                         *((char*)dest + num) = *((char*)src + num);
  11.                 }
  12.         }
  13.         else
  14.         {
  15.                 //当源空间在后,重叠空间在前,从前往后拷贝
  16.                 while (num--)
  17.                 {
  18.                         *(char*)dest = *(char*)src;
  19.                         dest = (char*)dest + 1;
  20.                         src = (char*)src + 1;
  21.                 }
  22.         }
  23.         return ret;
  24. }
复制代码

这里字节大小是23,大家觉得有问题莫?
没有由于我们强制转化的时候是char*,单元是1个字节,已经高瞻远瞩到现在的情况了。
如果是int*的情况,则
 

总结:

本章节讲解了memcpy和memmove函数,也实现了他们的模仿实现。


  • 内存复制函数——memcpy
  • 内存移动函数——memmove
今天的内容到这里就全部结束啦,在下章为大家讲解剩下的三个函数。
如果大家喜欢博主的内容,可以点赞、收藏加批评支持一下博主,固然也可以将博主的内容转发给你身边必要的朋友。
最后感谢各位朋友的支持,咱们下章再见!!!




 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

泉缘泉

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表