C语言内存函数

前言

上篇博客我们分析了字符函数和字符串函数,这篇咱们就来看看内存函数

个人主页:小张同学zkf

若有问题,评论区见

感兴趣就关注一下吧


目录

[1. memcpy使用和模拟实现](#1. memcpy使用和模拟实现)

[2. memmove使用和模拟实现](#2. memmove使用和模拟实现)

[3. memset函数的使用](#3. memset函数的使用)

[4. memcmp函数的使用](#4. memcmp函数的使用)


1. memcpy使用和模拟实现

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

这个函数有点类似于上篇博客的strncpy,但是strncpy只能拷贝字符串的,而咱们现在遇到的函数是memcpy,这个没有具体拷贝什么,它的功能就是将一个内存块里的数据拷贝到另一个内存块

注意:

• 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。

• 这个函数在遇到 '\0' 的时候并不会停下来。

•若这俩内存块有重叠,那复制的结果都是未定义的

我们可以看一个例子

#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, 20);

int i = 0;

for (i = 0; i < 10; i++)

{

printf("%d ", arr2[i]);

}

return 0;

}

这里需要强调一下,一个int类型是4个字节,那拷贝20个字节相当于将5个整形拷贝过去!!!

所以这个结果就是 把1,2,3,4,5前五个整形拷贝过来

我们来看看memcpy模拟实现

我们首先要知道第二个参数指针指向的对象不能改变,它是要拷贝的东西,其次这个函数是什么类型都能接受的,所以参数类型用void*来接受,那返回目的地的指针也是void*,然后这个函数是一个字节一个字节的拷贝,所以我们要强制转换成char*类型,因为char*解引用访问的空间就是一个字节

void * memcpy ( void * dst, const void * src, size_t count)

{

void * ret = dst;

assert(dst);

assert(src);

/*

* copy from lower addresses to higher addresses

*/

while (count--) {

*(char *)dst = *(char *)src;

dst = (char *)dst + 1;

src = (char *)src + 1;

}

return(ret);

}

2. memmove使用和模拟实现

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

这个函数其实只跟memcpy有一个差别,这个函数源内存块和目标内存块是可以重叠的,而memcpy不能重叠

注意:

• 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。

• 如果源空间和目标空间出现重叠,就得使⽤memmove函数处理。

我们来看一下这个函数的模拟实现

这个函数我们分析一下,拷贝的时候要注意不要覆盖源内存块的内容,我么画图来看一下

这个就是覆盖上了导致不是我们想要的拷贝,这是从前向后拷贝的,从3开始向后拷贝的,那我们换个方向拷贝,从后向前拷贝试试呢

这个就没有覆盖,这个就是从后向前,就是这个是从5开始向前拷贝的,但我们再想想真的所有情况都适合于 从后向前拷贝的吗,从后想前拷贝就不会出现覆盖吗

我们来看一下这种情况

这种情况从后向前拷贝也就是从5开始向前拷贝就被覆盖了,返而这种情况从前向后拷贝不被覆盖

那我们是不是就应该总结一下,什么时候从前向后拷贝不用担心覆盖,什么时候从后向前拷贝不用担心覆盖

我们对比一下这几张图发现,目标空间首指针小于源空间的首指针时应从前向后拷贝才正常,而目标空间首指针大于源空间的首指针时,应从后向前拷贝才正常

所以if条件有了,在从后向前拷贝时记得将地址加到拷贝的最后一位

以下是代码

void * memmove ( void * dst, const void * src, size_t count)

{

void * ret = dst;

if (dst <= src || (char *)dst >= ((char *)src + count)) {

/*

* Non-Overlapping Buffers

* copy from lower addresses to higher addresses

*/

while (count--) {

*(char *)dst = *(char *)src;

dst = (char *)dst + 1;

src = (char *)src + 1;

}

}

else {

/*

* Overlapping Buffers

* copy from higher addresses to lower addresses

*/

dst = (char *)dst + count - 1;

src = (char *)src + count - 1;

while (count--) {

*(char *)dst = *(char *)src;

dst = (char *)dst - 1;

src = (char *)src - 1;

}

}

return(ret);

}

3. memset函数的使用

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

这个函数就是将第一个参数的内存块设置成num个字节的第二个参数这个整形值

我们来看一下这个函数是如何使用的

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

结果

xxxxxxworld

4. memcmp函数的使用

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

比较内存块里数据的大小,记住是一个一个字节比较的!!!
注意:

• 比较从ptr1和ptr2指针指向的位置开始,向后的num个字节

• 返回值如下:

我们来看看这个函数的使用

#include <stdio.h>
#include <string.h>
int main()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n = memcmp(buffer1, buffer2, sizeof(buffer1));
if (n > 0)
printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
else if (n < 0)
printf("'%s' is less than '%s'.\n", buffer1, buffer2);
else
printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
return 0;
}

结束语

这篇博客内存函数要和上一篇博客字符串函数区分清楚,可以对比区分一下

OK感谢观看

相关推荐
乌啼霜满天2491 分钟前
JDBC编程---Java
java·开发语言·sql
色空大师14 分钟前
23种设计模式
java·开发语言·设计模式
Bruce小鬼27 分钟前
QT文件基本操作
开发语言·qt
2202_7544215432 分钟前
生成MPSOC以及ZYNQ的启动文件BOOT.BIN的小软件
java·linux·开发语言
我只会发热39 分钟前
Java SE 与 Java EE:基础与进阶的探索之旅
java·开发语言·java-ee
懷淰メ1 小时前
PyQt飞机大战游戏(附下载地址)
开发语言·python·qt·游戏·pyqt·游戏开发·pyqt5
hummhumm1 小时前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
宁静@星空1 小时前
006-自定义枚举注解
java·开发语言
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
武子康2 小时前
Java-07 深入浅出 MyBatis - 一对多模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据库·sql·mybatis·springboot