内存函数
1.memcpy的使用和模拟实现
2.memmove的使用和模拟实现
3.memset的使用
4.memcmp的使用和模拟实现
1.memcpy的使用和模拟实现
在前两篇我们学习了字符串函数和字符函数,那么对于不是字符类型的数据或者不清楚的数据类型,当我们想要对他们进行拷贝,比较时应该怎末办呢?
C语言也为我们提供了内存函数,来处理这些问题。
先介绍memcpy函数
函数声明:
void* memcpy(void* destination,void* source,size_t num);
通过函数声明,可以看得出来他跟memncpy函数十分相似,无非就是适用的数据类型不同而已。
但并非如此
注意:
1.这个函数在遇到’\0’时并不会停下来
2.当destination和source出现重叠时,结果就是未定义的
3.函数memcpy从source的位置开始向后复制num个字节的数据到desitination 指向的内存位置
函数使用
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
memcpy(arr2, arr1, 5);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
那通过调试,就会清楚输出结果为 1 2 0 0 0 0 0 0 0 0
函数的模拟实现
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memcpy(void* dest,const void* str, size_t num)
{
void* m = dest;
assert(dest);
assert(str);
while (num)
{
*(char*)dest = *(char*)str;
dest = (char*)dest + 1;
str = (char*)str + 1;
num--;
}
return m;
}
//
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
my_memcpy(arr2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
2.memmove的使用和模拟实现
在上边memcpy强调了destination与source是不能出现重叠的,那如果出现重叠又要怎样实现呢?
这就不得不请出memmove了
memmove与memcpy的区别就是memmove处理的源内存块和目标内存块可以重叠
函数声明:
void* memmove(void* destination,void* source,size_t num);
函数使用
#include<stdio.h>
#include<string.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr + 3, arr, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
函数模拟实现
分析一波
如图所示,dest作为目标空间,str作为源空间
dest与str的关系无非就3种。
第一种就是红色箭头所示,dest>str时,我们就可以把str的数据一个字节一个字节的拷贝给dest,并不会因为拷贝过去的字节覆盖之前的字节而影响效果
第二种就是dest>(char*)str+count,这时候,dest与str已经不再重叠,那就和第一种一样,将字节逐一拷贝过去就可以
第三种str<dest<(char*)str+count,
如果我们还像第一种那样,按照粉色箭头把str的数据一点点拷贝到destination 中,就会出现一个问题
那就是当我们把第一个数据拷贝过去后,再拷贝第二个数据就会发现原来的第二个数据已经被之前拷贝过去的数据覆盖了
因此可以通过改变开始拷贝的起点来避免这种情况的发生。
将起点改变成(char*)dest+count-1,和(char*)str+count-1,然后反着将str的数据拷贝到dest的空间就可以了
函数模拟实现
void* my_memmove(void* dest, void* str, size_t num)
{
void* m = dest;
if (dest <= str || (char*)dest >= ((char*)str + num))
{
while (num)
{
*(char*)dest = *(char*)str;
dest = (char*)dest + 1;
str = (char*)str + 1;
num--;
}
}
else
{
dest = (char*)dest + num - 1;
str = (char*)str + num - 1;
while (num)
{
*(char*)dest = *(char*)str;
dest = (char*)dest - 1;
str = (char*)str - 1;
num--;
}
}
return m;
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr + 2, arr, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
3.memset的使用
memset是用来设置内存的,将内存中的值以字节为单位设置成想要的内容
函数声明:
void* memmove(void* destination,void* source,size_t num);
函数使用
int main()
{
char s[20] = "hello world";
memset(s, 'w', 5);
printf("%s\n", s);//输出wwwww world
return 0;
}
但是这个字符常量不能是一个字符串
4.memcmp的使用和模拟实现
函数声明:
int memcmp(const void* str1,const void* str2,size_t num);
比较从str1和str2指针指向的位置开始,向后的num个字节
返回值:
函数使用:
int main()
{
char s[20] = "hello world";
char m[20] = "hello worid";
int ret = memcmp(s, m, 11);
printf("%d\n", ret);
}
函数模拟实现
int my_memcmp(void* ptr1, void* ptr2, size_t num)
{
int count = 0;
while (*(char*)ptr1 == *(char*)ptr2)
{
ptr1 = (char*)ptr1 + 1;
ptr2 = (char*)ptr2 + 1;
count ++ ;
if (count == num)
return 0;
}
return *(char*)ptr1 - *(char*)ptr2;
}
int main()
{
char s[20] = "hello world";
char m[20] = "hello worid";
int ret=my_memcmp(s, m, 5);
printf("%d\n", ret);
return 0;
}
内存函数和字符串函数基本大同小异,因此学起来也比较容易,只要多加练习能熟练掌握在日常写代码的过程中就可以了
作者有话说:作者只是一只小白,以上均是在学习完后对知识的理解,如有错误和不足,感谢指出;若觉得有帮助,可以留下一个👍,一起加油!