1.memcpy使用和模拟实现
memcpy函数的功能
函数memcpy同样是实现内容拷贝,但与strcpy函数不同,memcpy可以实现任何类型数据的拷贝
memcpy函数的函数原型
void *memcpy(void * destination,const void *source,size_t num);
可以看到,函数的第一个参数是拷贝目标的首地址,第二个参数是拷贝对象的首地址,第三个参数是拷贝的长度。
memcpy函数使用的注意事项
1.函数的拷贝是以字节为单位的,也就是说,函数的第三个参数填入的是拷贝字节的大小,比如我们要拷贝一个整型数组的第一个元素到另外一个整型数组里面
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9 };
int arr2[5] = { 0 };
memcpy(arr2, arr1, 4);//这个参数就是4
int i;
for (i = 0; i < 5; i++)
{
printf("%d ",arr2[i]);
}
return 0;
}
这里我是要拷贝一个元素,一个整型元素的大小是4个字节,因此第三个参数是4;
2.如果source和idstinatio的空间有任何的重叠,复制的结果都是未定义的
直接上代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9 ,10};
memcpy(arr1+2, arr1, 20);//这里的destination和source重叠了,就是空间有交叉的部分
int i;
for (i = 0; i < 10; i++)
{
printf("%d ",arr1[i]);
}
return 0;
}
//我们预期的结果是1 2 1 2 3 4 5 8 9 10
//但是结果却是1 2 1 2 1 2 1 8 9 10,因为本该复制的第三个元素3却被前面的拷贝修改成了1,所以内容改变了
但是我们在vs上运行这串代码的时候发现却没有问题,这并不是讲解有什么错误,而是memcpy超额完成了任务,从memcpy的原型来说的确是不行的,但是vs能够优化这些问题,所以我们这样的代码也完成了我们的预期。
3.这个函数在遇到了'\0'的时候并不会停下来
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
char arr1[] = "abscsdffd";
char arr2[5] = { 0 };
memcpy(arr2, arr1+8, 5);
int i;
for (i = 0; i < 5; i++)
{
printf("%c ",arr2[i]);
}
return 0;
}
发现运行后的结果是这个:
memcpy函数的模拟实现
void* my_memcpy(void* des, const void* src, size_t count)
{
void* ret = des;
assert(des && src);
while (count--)
{
*(char*)des = *(char*)src;
des = (char*)des + 1;
src = (char*)src + 1;
}
return ret;
}
//当然断言assert需要包含<assert.h>的头文件
2.memmove使用和模拟实现
memove函数的功能
可以说是移动内存,也可以说是拷贝内存,功能和memcpy函数的功能差不多,但是就是memmove函数处理的源内存块和目标内存块空间是可以重叠的
memmove函数的函数原型
void * memmove ( void * destination, const void * source, size_t num );
memmove函数的使用举例
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9 ,10};
memmove(arr1+2, arr1, 20);
int i;
for (i = 0; i < 10; i++)
{
printf("%d ",arr1[i]);
}
return 0;
}
也就是说如果我们要拷贝的内存空间存在重叠的话就用memmove函数
memmove函数的模拟实现
void * memmove ( void * dst, const void * src, size_t count)
{
void * ret = dst;
if (dst <= src || (char *)dst >= ((char *)src + count))
{
while (count--)
{
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
}
else
{
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);
}
第一个if也就是内存空间不存在重叠的情况,重点说明一下第二个内存存在重叠的情况
从后面先拷贝,这样就不会发生拷贝值被修改的问题
3.memset函数的使用
memset函数的功能
memset函数是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。也就是用来修改内容的。
memset函数的原型
void * memset ( void * ptr, int value, size_t num );
第一个参数也就是目标空间的地址,第二个参数是你要修改的内容,第三个参数是你要修改的字节数。
memset函数的使用举例
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
char str[] = "hello world";
memset(str, 'x', 5);
puts(str);
return 0;
}
得到的结果是
这个需要注意的是一定是以字节为单位进行修改的,再以改变一个整数为例
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
int a = 100;
memset(&a, 1, 2);
printf("%d", a);
return 0;
你以为结果会是“1”嘛,但不是的。
为什么是257呢,因为已经说了memset是以字节为单位进行修改,整型是4个字节,因此在修改之前它在计算机里面的存储是
这也就充分说明了memset函数的原理
4.memcpy函数的使用
memcpy函数的功能
按字节来比较大小。
memcpy函数原型
int memcmp ( const void * ptr1, const void * ptr2, size_t num )
第一和第二个参数是要比较的地址,第三个参数是要比较的字节长度
memcpy函数的返回值说明
如果ptr1大于ptr2则返回一个大于0的数;
如果ptr1等于ptr2则返回0;
如果ptr1小于ptr2则返回一个小于0的数;
memcpy函数的使用举例
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n = memcmp(buffer1, buffer2, sizeof(buffer1));
printf("%d", n);
return 0;
}