memcpy

包含在头文件<string.h>中
语法格式

1
void * memcpy ( void * destination, const void * source, size_t num );
  • 从 source 的位置开始拷贝 num 个字节的数据到 destination 指向的位置

    1
    2
    3
    4
    5
    6
    7
    8
    //memcpy 针对内存块进行拷贝
    int arr1[] = { 1,2,3,4 };
    int arr2[4] = { 0 };
    memcpy(arr2, arr1, 4 * sizeof(int));
    for (int i = 0;i < 4;i++)
    {
    printf("%d ", arr1[i]);
    }

  • 遇到 ‘\0’ 不会停下来

  • 如果 destination 和 source 有任何的重叠,拷贝的结果是未定义的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 如果 destination 和 source 有任何的重叠,拷贝的结果是未定义的
    int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
    // 这里拷贝空间出现了重叠
    memcpy(arr1 + 2, arr1, 4 * sizeof(int));
    for (int i = 0;i < 10;i++)
    {
    // 虽然完成了目标,但是C语言中明确说明了 memcpy 就是用来拷贝不重叠的内存块的,
    // 所以不要这么用 memcpy
    printf("%d ", arr1[i]);
    }


    C语言中明确说明了 memcpy 就是用来拷贝不重叠的内存块的, 所以不要这么用 memcpy

模拟实现 memcpy

简单模拟一下 memcpy 的基本功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void* my_memcpy(void* destination, const void* source, size_t num)
{
// 传进来的指针类型不确定是具体类型,那就一个字节一个字节的进行拷贝
// 用一个变量 ret 记录 destination 的起始地址
void* ret = destination;
while (num--)
{
// 强转成 char* 类型进行拷贝
*(char*)destination = *(char*)source;
(char*)source = (char*)source + 1;
(char*)destination = (char*)destination + 1;
}

return ret;
}

int main()
{
int arr1[] = { 6,7,8,9 };
int arr2[4] = { 0 };
my_memcpy(arr2, arr1, sizeof(int) * 4);
for(int i = 0;i < 4;i++)
{
printf("%d ", arr2[i]);
}
return 0;
}

memmove

包含在头文件 <string.h> 中,与 memcpy 类似,但是支持内存块重叠的拷贝

语法格式

1
void * memmove ( void * destination, const void * source, size_t num );
1
2
3
4
5
6
7
// memmove 是可以进行内存空间叠加的拷贝
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1 + 4, arr1, 4 * sizeof(int));
for (int i = 0;i < 10;i++)
{
printf("%d ", arr1[i]);
}

memmove 的模拟

1
void* memmove(void* destination, const void* source, size_t num);

因为存在内存空间重叠,在进行内存空间拷贝时,核心逻辑就是先从不会影响后

续拷贝的内存空间起进行拷贝

第一种情况: source > destination



第二种情况: source < destination


当 destination 和 source 相同时用 source < destination 一样的拷贝方法,比较

容易就能想到这里不做演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
void* my_memmove(void* destination, const void* source, size_t num)
{
void* ret = destination;
//source > destination,从前往后拷
if (source > destination)
{
// 还是一个字节一个字节拷
while (num--)
{
*(char*)destination = *(char*)source;
(char*)source = (char*)source + 1;
(char*)destination = (char*)destination + 1;
}
}

else
{
//source <= destination,从后向后前拷
while (num--)
{
*((char*)destination + num) = *((char*)source + num);
}
}
return ret;
}

void print_Intarr(int arr[], int sz)
{
for (int i = 0;i < sz;i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}

int main()
{
// memmove 是可以进行内存空间叠加的拷贝
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr3[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr4[10] = { 1,2,3,4,5,6,7,8,9,10 };
int num = 4;
memmove(arr1 + 4, arr1, 4 * sizeof(int));
memmove(arr2, arr2 + 2, 4 * sizeof(int));
my_memmove(arr3 + 4, arr3, 4 * sizeof(int));
my_memmove(arr4 , arr4 + 2, 4 * sizeof(int));
print_Intarr(arr1, sizeof(arr1) / sizeof(arr1[0]));
print_Intarr(arr2, sizeof(arr2) / sizeof(arr2[0]));
print_Intarr(arr3, sizeof(arr3) / sizeof(arr3[0]));
print_Intarr(arr4, sizeof(arr4) / sizeof(arr4[0]));
return 0;
}

memset

包含在头文件 <string.h> 中

语法格式

1
void * memset ( void * ptr, int value, size_t num );

用来设置内存,将内存中的值以字节为单位设置成 value

1
2
3
char str[] = "hello world";
memset(str, 'x', 6);
printf(str);

memcmp

包含在头文件 <string.h>中
语法格式

1
int memcmp ( const void * ptr1, const void * ptr2, size_t num );

比较从 ptr1 和 ptr2 起向后的 num 个字节

  • 若 ptr1 < ptr2 ,返回 < 0 的值

  • 相等返回 0

  • 若 ptr1 > ptr2 ,返回 > 0 的值

  • 比较依据是指针指向的内容不等时的大小

1
2
3
4
5
6
7
8
9
10
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";
int n;
n = memcmp(buffer1, buffer2, sizeof(buffer1));
if (n > 0)
printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
else if (n < 0)
printf("'%s' is less than '%s'.\n", buffer1, buffer2);
else
printf("'%s' is the same as '%s'.\n", buffer1, buffer2);