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感谢观看

相关推荐
罗伯特祥4 分钟前
C调用gnuplot绘图的方法
c语言·plot
小_太_阳19 分钟前
Scala_【2】变量和数据类型
开发语言·后端·scala·intellij-idea
直裾22 分钟前
scala借阅图书保存记录(三)
开发语言·后端·scala
唐 城43 分钟前
curl 放弃对 Hyper Rust HTTP 后端的支持
开发语言·http·rust
嵌入式科普1 小时前
嵌入式科普(24)从SPI和CAN通信重新理解“全双工”
c语言·stm32·can·spi·全双工·ra6m5
码银2 小时前
【python】银行客户流失预测预处理部分,独热编码·标签编码·数据离散化处理·数据筛选·数据分割
开发语言·python
从善若水3 小时前
【2024】Merry Christmas!一起用Rust绘制一颗圣诞树吧
开发语言·后端·rust
lqqjuly3 小时前
特殊的“Undefined Reference xxx“编译错误
c语言·c++
2401_858286113 小时前
115.【C语言】数据结构之排序(希尔排序)
c语言·开发语言·数据结构·算法·排序算法
Jelena技术达人4 小时前
Java爬虫获取1688关键字 item_search接口返回值详细解析
java·开发语言·爬虫