1. memcpy使用和模拟实现
头文件是<string.h>,void* memcpy( void* destination,const void* source,size_t num);
- 这个参数是用来拷贝内存的,显而易见类型都是void*,他可不会管里面存的是什么数据,只负责拷贝内存里的数据。
- 每个参数对应的意思:destination表示目标地址 source表示源地址 size_t表示拷贝的大小,单位(字节)从源地址拷贝到目标地址
- 假如拷贝重叠部分的数据,这个就不归memcpy函数管了,归下面的memmove来处理
-
#include <string.h> int main() { char arr[] = "safgftdf"; char arr2[20] = ""; memcpy(arr2, arr, 4); printf("%s", arr2); return 0; }
上面代码运行的结果是 safg,只会拷贝四个字符
-
接下来是模拟实现
-
传参部分要和实参对应上,特么要注意的是size_t的参数部分,写成5 * sizeof(int)会更好,但是写成 20字节也没问题。
-
函数内代码解释:
-
sum直接解释为拷贝次数,当然是一个一个字节拷贝
-
为什么用强制转换(char*)指针呢,而不用int*呢,因为这样可以用于多种类型,就比如:假如是9个字节呢?那怎么办?那不就数据缺失了,char类型刚好是1个字节,所以可以面对更多的情况
void* my_memcpy(void* dest,const void* src,size_t sum) { assert(dest && src);//判断是否为NULL,否则报错 while (sum--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1; src = (char*)src + 1; } } int main() { //memcpy模拟实现 int sum[] = { 1,2,3,4,5,6,7,8,9 }; int src[] = { 6,6,6,6,6 }; my_memcpy(sum, src, 5 * sizeof(int)); int sz = sizeof(sum) / sizeof(sum[0]); for (int i = 0; i < sz; i++) { printf("%d ", sum[i]); } return 0; }
-
2. memmove使用和模拟实现
void * memmove ( void * destination, const void * source, size_t num );
- 这个就是上面所说的,重叠部分用memmove函数更好,而且同样也可以实现memcpy的功能
- 那么这个函数对应参数是什么呢?其实和上面一个函数一样
- dest是目标地址,src是源地址 ,接下来我就用动图来解释一下原理
- 可以设想一下错误的:你按照从3 --> 5 4 --> 6 ,5 --> 7?真的5会过去吗,其实之前的3已经覆盖了 就变成了 3 (拷贝)-- > 7,那最终错结果会是 1 2 3 4 3 4 3 8 9
由上面两个图可以得出结论:
1.当dest > src 时 用数组的最后一个元素向目标元素最后拷贝
2.当 dest < src 时,用数组的前面的元素向目标前元素拷贝
最后是代码的实现:
my_memmove(void* dest, void* src, size_t sum)
{
assert(dest && src);
void* ret = dest;//返回目标空间地址
if (dest > src)//从后向前拷贝
{
while (sum--)
{
*((char*)dest + sum) = *((char*)src + sum);//当前地址长度 + sum访问到数组的最后一个字节,然后对其解引用
}
}
else//dest < src ,从数组的前面向后拷贝
{
while (sum--)
{
*(char*)dest = *(char*)src;
((char*)dest)++;//解释:先对其强制转换,然后再++;(char*)dest++,没有意义因为先 ++,再强制类型转换有什么用?
((char*)src)++;
}
}
return ret;
}
int main()
{
//memmove函数模拟实现
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };//3 4 5 6 7 6 7 8 9 10,这个是数组从前向后拷贝,dest < str
int* reet = (int*)my_memmove(arr1 , arr1 + 2, 5 * sizeof(int));
for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
{
printf("%d ", *(arr1 + i));
}
return 0;
}
3. memset函数的使用
void * memset( void * ptr, int value, size_t num );
int main()
{
//memset的使用
char arr[] = "abcdefg";
memset(arr, 'Y', 3);
//printf("%s", arr);
int sum[] = { 1,2,3,4,5,6,7,8 };
memset(sum, 2, 32);//内存的每个字节设置成 1,这个是设置内存
for (int i = 0; i < 8; i++)
{
printf("%d ", sum[i]);
}
return 0;
}
- 因为这个函数不常用,就讲讲用法吧。memset,他是一个设置内存块的函数的
- 再来解释一下对应参数:ptr指向内存块的 value你要设置的值 size_t设置多少个字节
- 上面代码的运行结果是: YYYdefg
- 下面的结果估计你想不到,其实它是给每个字节设置成2,也就意味着结果变成了 二进制的:00000010000000100000001000000010 --> 换算成10进制:33,686,018。
- 也就意味着它就是按照每个内存块来设置的
4. memcmp函数的使用
int memcmp(const void* ptr1, const void* ptr2, size_t num);
int main()
{
//memcmp,对比内存中数据的大小
int s1[] = { 1,2,3,4,5,6,7,8 };
int s2[] = { 1,2,3,4,6,6,6,6 };
int ret = memcmp(s1, s2, 17);
if (ret > 0)
printf("1比2大");
else if (ret < 0)
printf("1比2小");
else
printf("相等");
return 0;
}
- 比对内存中的数据大小
- 上面代码可以很好的说明了,s2 > s1;可能你会想为什么是17个字节啊,这数据不是不匹配吗
- 其实不然,因为拿到了数字6的第一个字节,而vs编译器中是以小段字节序存储的,自然会拿低地址的数据去比对
- 在内存中站在了地址低处
总结:一起加油吧!!!