一、memcpy-内存拷贝1
1.函数介绍
void* my_memcpy(void* dest,const void* src,size_t sz);
memcpy函数是将src指向的sz个字节大小的内容拷贝到dest中,并返回dest的地址。
注意:
1.该函数的指针类型全部设置为void*,内存函数不同于字符串函数,操作的对象不仅仅是字符串,可能是整形,结构体等等,所以拿空指针来接收(下文不再赘述);
2.dest指向的空间一定要足够大,要放的下拷贝的src指向的内容;
3.该函数由于设置了第三个参数来规定拷贝数据的大小,故遇到‘\0’不会停下来。
举个栗子,我们将arr2中前16个字节拷贝到arr1中。
int main()
{
int arr1[10] = {0};
int arr2[] = { 1,2,3,4,5,6 };
memcpy(arr1, arr2, 16);
int i = 0;
for (i = 0; i < 4; i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
return 0;
}
运行结果
2.模拟实现
void* my_memcpy(void* dest,const void* src,size_t sz)
{
void * ret = dest;
assert(dest && src);//dest和src有一方为空指针就报错
while (sz--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
注意:
1.函数返回目标函数的起始位置即最初的dest,但随着拷贝的进行dest发生变化,所以最初要创建一个ret指针来记录最初位置;
2.关于拷贝过程中的强制类型转换到char*类型的单位化值得体会,指针的类型决定了指针解引用的步调,举个例子,像char*类型的指针解引用后会向后找一个char类型大小(即一个字节大小)的数据,或者说从指针指向的位置向后找一个字节的数据,而int*的指针类型解引用向后找一个int类型的大小的数据即从指针指向的位置向后找四个字节的数据。回到前文提到的内存函数的操作对象上,可能是整型,可能是结构体等等,那如何拷贝呢?联系上文不难想出,我们可以单位化的来逐字节的拷贝,因为字节在这里是最小的操作单元,其余类型都是一字节的整数倍(后文不再赘述);
3.逐字节拷贝我们可以放在一个循环里来解决,循环次数即sz的大小,sz为0表达式为假跳出循环,注意后置--是先使用后--。
二、memmove-内存拷贝2
1.函数介绍
void* memmove(void* dest, void* src, size_t sz);
memmove函数是同样是将src指向的sz字节的内容放到dest中并返回相应地址,观察参数也是与memcpy的一样,那二者区别在哪里呢?
先来看一段代码实现
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
memmove(arr + 2, arr, 20);
int i = 0;
for (i = 0; i < 9; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
运行结果
通过观察不难发现原数组的3,4,5,6,7被覆盖成了1,2,3,4,5即arr+2指针指向的20个字节被arr指向的20个字节覆盖。memcpy是实现源内存块与目标内存块不重叠的拷贝,而memmove是在源内存块与目标内存块有重叠的情况下的以另一种方式实现的拷贝。
2.模拟实现
首先我们任给定一个src的位置,同时找到src往后的sz个字节大小指向的位置,将这两个位置作为我们讨论的边界。
我们给定了src的位置但并未给定dest的位置,讨论的问题即dest在这两个边界划分的不同不同区域,拷贝的逻辑是怎样的。
未重叠类:
第三类:dest指向的内容未与src指向的内容重叠,拷贝顺序前向后或后向前均可;
有重叠类:
第二类:dest指向的内容与src有重叠且dest在src右边,从后往前拷贝才能保证在拷贝过程中源内存块内容不被覆盖的拷贝到目标内存块中;
第一类:dest指向的内容与src有重叠且dest在src左边,从前往后拷贝才能保证在拷贝过程中源内存块内容不被覆盖的拷贝到目标内存块中;
void* memmove(void* dest, void* src, size_t sz)
{
void* ret = dest;
assert(dest && src);
if (dest < src)
{
//前->后
while (sz--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//后->前
while (sz--)
{
*((char*)dest+sz) = *((char*)src + sz);
}
}
return ret;
}
三、memcmp-内存比较
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
memcmp函数是一个用于比较两个内存块大小的函数。它会比较从buf1和buf2指针开始的num个字节,当buf1大于buf2的时候返回一个大于0的数,当buf1等于buf2的时候返回0,当buf1小于buf2的时候返回一个小于0的数(实际比较的是对应位置的ascll码值的大小)。
举个例子
#include <stdio.h>
#include <string.h>
int main()
{
int arr1={1,2,3,4};
it arr2={1,2,4,5};
int ret1=memcmp(arr1,arr2,8);
int ret2=memcmp(arr1,arr2,9);
return 0;
}
注意:vs下采取小端排序
四、memset-内存设置
void * memset ( void * ptr, int value, size_t num );
memset函数ptr指向要设置的起始位置,value是指要设置的内容(可以直接传字符,字符也属于整形家族,实际存储的是其ASCII码值),num是指要设置的字节数。
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "almost every programmer should know memset!";
memset (str,'-',6);
puts (str);
return 0;
}
运行结果