跨境派

跨境派

跨境派,专注跨境行业新闻资讯、跨境电商知识分享!

当前位置:首页 > 工具系统 > 数据分析 > C语言——内存函数

C语言——内存函数

时间:2024-04-19 21:40:18 来源:网络cs 作者:言安琪 栏目:数据分析 阅读:

标签: 函数  语言 

引言

在之前的两篇文章中,我们学习了字符函数和字符串函数,C语言中还有一类库函数叫做内存函数

我们接下来去学习一下这类函数

内存函数

内存函数的功能和某些字符函数的功能相似,它们是通过访问地址的方式操作对象,可应用于任何类型的对象。它们的使用需要包含头文件<string.h>

memcpy

1.memcpy的用法

memcpy用于内存拷贝。它的主要作用是将指定源地址处的内容复制到指定的目标地址处,即将一段内存中的数据拷贝到另一段内存中。

函数原型为:

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

其中,其参数的含义如下:

destination:指向目标内存区域的指针,即要接收源内存内容的位置

source:指向源内存区域的指针,即要复制的内容所在的起始位置

num:要拷贝的字节数

返回值:

返回一个指向目标内存区域destination的指针

功能:

函数memcpy从source的位置开始向后赋值num个字节的数据到destination指向的内存位置

注意:

memcpy不会对目标内存进行初始化或清除,只是简单地覆盖指定大小的字节

如果源地址和目标地址重叠,则memcpy的行为是未定义的。在这种情况下,应该使用memmove函数

使用memcpy时,必须确保目标内存区域destination有足够的空间来容纳要复制的n个字节,否则会导致缓冲区溢出,引发程序错误或安全漏洞

2.memcpy的使用

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

输出结果为:

0 1 2 3 4 0 0 0 0 0

3.memcpy的模拟实现

思路:与strncpy类似,只不过memcpy是将指定长度的内存内容到目标地址,并返回目标地址的起始位置。

代码实现如下:

void* my_memcpy(void* dest,const void* src, int n){void* ret = dest;assert(dest && src);//循环复制内存内容,直到复制了 n 个字节while (n--){// 将源地址的当前字节复制到目标地址的当前位置 *(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return ret;}int main(){int arr1[] = { 0,1,2,3,4,5,6,7,8,9 };int arr2[20] = { 0 };my_memcpy(arr2, arr1, 20);for (int i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;}

memmove

1.memmove的用法

memmove用于在内存中移动(复制)字节块。它的主要用途是处理源和目标内存区域重叠的情况,这是 memcpy 函数无法处理的

函数原型为:

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

其中,其参数的含义如下:

destination:指向目标内存区域的指针,即要接收源内存内容的位置

source:指向源内存区域的指针,即要复制的内容所在的起始位置

num:要拷贝的字节数

返回值:

memmove 函数返回指向目标内存区域的指针,即 destination

注意:

使用 memmove 时,即使源和目标内存区域重叠,它也能正确复制数据。这是因为 memmove 可能会采用不同的策略来确保数据的一致性和正确性,比如先临时存储源数据,然后再复制到目标位置

2.memmove的使用

int main(){int arr[] = { 0,1,2,3,4,5,6,7,8,9 };memmove(arr + 2, arr, 20);for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;}

输出结果为:

0 1 0 1 2 3 4 7 8 9

解释:

memmove 将数组的前5个整数(0, 1, 2, 3, 4)复制到了从第三个位置开始的内存

int main(){int arr[] = { 0,1,2,3,4,5,6,7,8,9 };memmove(arr, arr + 2, 20);for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;}

输出结果为:

2 3 4 5 6 5 6 7 8 9

解释:

由于memmove将数组从第三个元素开始的五个整数(2, 3, 4, 5, 6)复制到了数组的开始位置

3.memmove的模拟实现

我们现在已经大概理解了memmove的用法,现在我们来试着模拟实现memmove

我们先来分析一下:

情况1:

    int arr[] = { 0,1,2,3,4,5,6,7,8,9 };memmove(arr + 2, arr, 20);

从2的位置开始拷贝:2->0  3->1  4->2  5->3  6->4 拷贝成功

从6的位置开始拷贝:6->4  5->3  4->2  3->1  2->0 拷贝失败

情况2:

int arr[] = { 0,1,2,3,4,5,6,7,8,9 };memmove(arr, arr + 2, 20);

从0的位置开始拷贝:0->2  1->3  2->4  3->5  4->6 拷贝失败

从4的位置开始拷贝:4->6  3->5  2->4  1->3  0->2 拷贝成功

情况3:

int arr[] = { 0,1,2,3,4,5,6,7,8,9 };memmove(arr, arr + 5, 20);

从5的位置开始拷贝:5->0  6->1  7->2  8->3  9->4 拷贝成功

从9的位置开始拷贝:9->4  8->3  7->2  6->1  5->0 拷贝成功

情况4:

int arr[] = { 0,1,2,3,4,5,6,7,8,9 };memmove(arr + 5, arr, 20);

从0的位置开始拷贝:0->5  1->6  2->7  3->8  4->9 拷贝成功

从4的位置开始拷贝:4->9  3->8  2->7  1->6  0->5 拷贝成功

我们可以根据这些情况得出结论:

如果dest在src左边,就从首元素开始拷贝;如果dest在src右边,就从末尾元素开始拷贝

代码实现如下:

void* my_memmove(void* dest, void* src, int num){    void* ret = dest;      assert(dest && src);     //判断目标地址是否小于或等于源地址      //如果是,则按照从前往后的顺序复制,防止覆盖还未复制的源数据      if (dest <= src)    {        //从前往后复制数据          while (num--) //循环num次,每次复制一个字节          {            *(char*)dest = *(char*)src; //将src指向的字节复制到dest指向的位置              dest = (char*)dest + 1; // 将dest指针向后移动一个字节              src = (char*)src + 1; // 将src指针向后移动一个字节          }    }    else    {        // 如果目标地址大于源地址,则按照从后往前的顺序复制          // 这样可以避免在复制过程中覆盖还未读取的源数据          dest = (char*)dest + num - 1; // 将dest指针移动到目标区域的最后一个要复制的字节          src = (char*)src + num - 1; // 将src指针移动到源区域的最后一个要复制的字节          while (num--)         {            *(char*)dest = *(char*)src; //将src指向的字节复制到dest指向的位置              dest = (char*)dest - 1; //将dest指针向前移动一个字节              src = (char*)src - 1; //将src指针向前移动一个字节          }    }    return ret; }int main(){int arr[] = { 0,1,2,3,4,5,6,7,8,9 };my_memmove(arr + 2, arr, 20);for (int i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;}

memset

1.memset的用法

memset用于将某一块内存中的内容全部设置为指定的值

函数原型为:

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

其中,其参数的含义如下:

ptr:指向要设置的内存区域的指针

value:要设置的值,该值被转换为 unsigned char 并复制到目标内存区域

num:要设置的字节数

返回值

返回指向被设置内存区域的起始位置的指针

注意:

memset 是按字节操作的,因此当你对非字符类型(如整数、浮点数等)的数组使用 memset 时,需要特别小心。确保你了解目标数组的类型,并知道如何正确地初始化它。对于非零初始化,特别是非字符类型,memset 可能不会按预期工作。

2.memset的使用

int main(){char arr[] = "hello world";memset(arr, 'x', 5); //将前5个字符替换为'x'printf("%s\n", arr); //打印修改后的字符串return 0;}

输出结果为:

xxxxx world

错误演示:

int main(){int arr[5] = { 1,2,3,4,5 };memset(arr, 1, sizeof(arr));int i = 0;for (i = 0; i < 5; i++){printf("%d ", arr[i]);}return 0;}

输出结果为:

16843009 16843009 16843009 16843009 16843009

memset设置是以字节为单位,容易造成不符合我们预期的情况

3.memset的模拟实现

思路:memset的模拟实现和strncpy有点相似,但memset需要将数据类型强制转换为(char*)

代码如下:

void* my_memset(void* str, int c, size_t n){    assert(str);    // 将void*类型的指针转换为char*类型的指针,以便按字节访问      char* tmp = (char*)str;    // 使用while循环遍历n个字节      while (n--)    {        // 将当前字节设置为字符c          *tmp = (char)c;        // 移动到下一个字节          tmp++;    }    return str;}int main(){    char str[] = "hello world";    my_memset(str, 'x', 6);    printf("%s\n", str);    return 0;}

memcmp

1.memcmp的用法

memcmp用于比较内存区域的内容

函数原型为:

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

其中,其参数的含义如下:

s1 和 s2 是指向要比较的内存区域的指针

n 是要比较的字节数

返回值:

返回值:

如果返回值 < 0,则表示 ptr1 小于 ptr2

如果返回值 > 0,则表示 ptr1 大于 ptr2

如果返回值 = 0,则表示 ptr1 等于 ptr2

注意:

memcmp 函数按字节比较两个内存区域的内容,而不是按数据类型或元素进行比较。因此,它对于比较任意类型的内存区域都是有效的,只要你知道要比较的字节数

2.memcmp的使用

int main(){int arr1[] = { 0,1,2,3,4,5,5,5 };int arr2[] = { 0,1,2,3,4,6,6,6 };int ret = memcmp(arr1, arr2, 21);printf("%d\n", ret);return 0;}

输出结果为:

-1

3.memcmp的模拟实现

思路:memcmp的模拟实现与strncmp差不多,只是也需要先强制类型转换

代码如下:

int my_memcmp(const void* str1, const void* str2, size_t n){assert(str1 && str2);char* p1 = (char*)str1;char* p2 = (char*)str2;while (n-- && (*p1 == *p2)){p1++;p2++;}return *p1 - *p2;}int main(){int arr1[] = { 0,1,2,3,4,3,6,7 };int arr2[] = { 0,1,2,3,4,2,4,4 };int ret = my_memcmp(arr1, arr2, 24);printf("%d\n", ret);char str1[] = "abcddd";char str2[] = "abcdef";ret = my_memcmp(str1, str2, 5);printf("%d\n", ret);return 0;}

输出结果为:

1
-1

结束语

希望看完这篇文章能对友友们有所帮助!!!

点赞收藏关注!!!

谢谢各位!!!

本文链接:https://www.kjpai.cn/news/2024-04-19/160495.html,文章来源:网络cs,作者:言安琪,版权归作者所有,如需转载请注明来源和作者,否则将追究法律责任!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。

文章评论