文章目录
- 1.memcpy使用和模拟实现
- 2.memmove使用和模拟实现
- 3.memset函数的使用
- 4.memcmp函数的使用
memcpy
:内存拷贝
memmove
:内存移动
memset
:内存设置
memcmp
:内存比较
1.memcpy使用和模拟实现
memcpy
:内存拷贝
void * memcpy ( void * destination, const void * source, size_t num );
目标空间的地址 源空间的地址 被拷贝的字节个数
返回的是目标空间的起始地址
void*指针接收任意参数的地址
函数
memcpy
从source
的位置开始向后复制num
个字节的数据到destination
指向的内存位置。这个函数在遇到 ‘
\0
’ 的时候并不会
停下来。如果
source
和destination
有任何的重叠,复制的结果都是未定义的。
#include <stdio.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num) {
int i = 0;
void* ret = dest;
assert(src && dest);
while (num--) {
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main() {
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
//将arr1中的34567拷贝到arr2中
my_memcpy(arr2, arr1 + 2, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
打印:
3 4 5 6 7 0 0 0 0 0
注意:对于重叠的内存,交给
memmove
来处理。重叠的意思就是:
my_memcpy(arr1 + 2, arr1, 20);
比如你想把
arr
数组里的某些数用arr
数组的某些数替换,这样会出问题。
例如:
void* my_memcpy(void* dest, const void* src, size_t num) {
int i = 0;
void* ret = dest;
assert(src && dest);
while (num--) {
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main() {
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
//我们的想法是:将arr1中的12345拷贝到arr1中原来34567的地方,将原来的覆盖
my_memcpy(arr1 + 2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
打印:
1 2 1 2 1 2 1 8 9 10
打印这个玩意儿?怎么和猜的不一样呢?
1 2 3 4 5 6 7 8 9 10
程序里先把1替换了3
1 2 1 4 5 6 7 8 9 10
然后2替换了4
1 2 1 2 5 6 7 8 9 10
然后原来3位置的1替换了5
1 2 1 2 1 6 7 8 9 10
然后原来4位置的2替换了6
1 2 1 2 1 2 7 8 9 10
然后原来5位置的1替换了7
1 2 1 2 1 2 1 8 9 10
memcpy
函数不负责重叠内存的拷贝,只负责不重叠的内存,非要使用,结果就是未定义的。
不过说是这么说,有些时候memcpy
也能实现重叠内存的拷贝。我们可以认为memcpy
实现的拷贝不一定都对。所以重叠就用memmove
函数。
memmove
函数来处理重叠内存的拷贝。
2.memmove使用和模拟实现
memmove
:内存移动
void * memmove ( void * destination, const void * source, size_t num );
和
memcpy
的差别就是memmove
函数处理的源内存块和目标内存块是可以重叠的。如果源空间和目标空间出现重叠,就得使用memmove函数处理。
#include <string.h>
int main() {
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
//将arr1中的12345拷贝到arr1中原来34567的地方,将原来的覆盖
memmove(arr1 + 2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
打印:
1 2 1 2 3 4 5 8 9 10
这个函数实际上就是实现src拷贝到dest。
如果是上面一种情况的话,我们可以先把3给1,然后把4给2,然后把5给3…这样就可以实现重叠内存的处理。(从前向后)
如果是中间一种情况的话,我们可以先把7给9,然后把6给8,然后把5给7…这样就可以实现重叠内存的处理。(从后向前)
如果是下面一种情况的话,我们可以按顺序把3给8,把4给9,把5给10…这样就可以实现重叠内存的处理。(从后向前)
两个紫色竖线表示的位置分别为
src
的起始位置和结束位置。这两根紫色竖线把情况分成了三种。
第一种情况是(从前向后)
第二种情况是(从后向前)
模拟实现:
void* my_memmove(void* dest, const void* src, size_t num) {
void* ret = dest;
assert(src && dest);
if (dest < src) {
while (num--) {
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else {
while (num--) {
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
int main() {
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
//将arr1中的12345拷贝到arr1中原来34567的地方,将原来的覆盖
my_memmove(arr1 + 2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
打印:
1 2 1 2 3 4 5 8 9 10
3.memset函数的使用
memset
:内存设置
void * memset ( void * ptr, int value, size_t num );
memset
是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "hello world";
memset (str,'x',6);
printf(str);
return 0;
}
打印:
xxxxxxworld
4.memcmp函数的使用
memcmp
:内存比较
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
比较从ptr1和ptr2指针指向的位置开始,向后的num个字节
返回值如下:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
int arr2[] = { 1,2,3,6,5 };
//01 00 00 00 02 00 00 00 03 00 00 00 06 00 00 00 05 00 00 00
int ret = memcmp(arr1, arr2, 12);
printf("%d\n", ret);
return 0;
}
打印:
0
因为前12个字节一样
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
int arr2[] = { 1,2,3,6,5 };
//01 00 00 00 02 00 00 00 03 00 00 00 06 00 00 00 05 00 00 00
int ret = memcmp(arr1, arr2, 13);
printf("%d\n", ret);
return 0;
}
打印:
-1
因为第13个字节不一样