目录

前言:

一、memcpy的使用和模拟实现

1.1 函数原型与基本使用

1.2模拟实现

二、memmove的使用和模拟实现

2.1函数原型与基本使用

2.2 模拟实现

三、memset函数的使用

3.1 函数原型与基本使用

四、memcmp函数的使用

4.1 函数原型与基本使用

五、内存函数的共性与适用场景总结


前言:

        在C语言中,内存函数是直接操作内存数据的底层工具,它们不关心数据的类型,仅以字节为单位处理内存块,因此具有极强的通用性和灵活性。下面我们逐一解析 memcpy 、 memmove 、 memset 和 memcmp 这四个核心内存函数的使用、原理与模拟实现。

一、memcpy的使用和模拟实现

memcpy 用于内存块的拷贝,将源内存块的内容按字节拷贝到目标内存块,声明在 <string.h> 头文件中。

1.1 函数原型与基本使用

 
void *memcpy(void *destination, const void *source, size_t num);

-  destination :目标内存块地址,需可修改且空间足够大。
-  source :源内存块地址,用 const 修饰表示只读。
-  num :拷贝的字节数( size_t 为无符号整数)。
- 返回值:返回 destination 的起始地址,支持链式操作。

示例:

#include <stdio.h>
#include <string.h>

int main() {
    int arr1[5] = {1, 2, 3, 4, 5};
    int arr2[5];
    // 拷贝arr1的20个字节(5个int,每个4字节)到arr2
    memcpy(arr2, arr1, 20);
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr2[i]); // 输出1 2 3 4 5
    }
    return 0;
}

1.2模拟实现

void *my_memcpy(void *dest, const void *src, size_t num) {
    void *ret = dest;
    // 强制转换为char*,以字节为单位操作
    char *d = (char *)dest;
    char *s = (char *)src;
    while (num--) {
        *d++ = *s++;
    }
    return ret;
}

注意:标准库 memcpy 不处理重叠内存块的拷贝(即源和目标内存区域有重叠时,结果未定义),若需处理重叠内存,需使用 memmove 。

二、memmove的使用和模拟实现

memmove 是 memcpy 的增强版,支持重叠内存块的拷贝,同样声明在 <string.h> 头文件中。

2.1函数原型与基本使用

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

参数和返回值与 memcpy 一致,但行为上能正确处理重叠内存

示例:

#include <stdio.h>
#include <string.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    // 源和目标内存重叠(将arr[0-3]拷贝到arr[1-4])
    memmove(arr + 1, arr, 16); // 拷贝4个int(16字节)
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]); // 输出1 1 2 3 4
    }
    return 0;
}
 

2.2 模拟实现

void *my_memmove(void *dest, const void *src, size_t num) {
    void *ret = dest;
    char *d = (char *)dest;
    char *s = (char *)src;
    // 情况1:目标内存在源内存后面(从后往前拷贝,避免覆盖未拷贝的源数据)
    if (d > s && d < s + num) {
        d = d + num - 1;
        s = s + num - 1;
        while (num--) {
            *d-- = *s--;
        }
    } 
    // 情况2:目标内存在源内存前面或无重叠(从前往后拷贝,同memcpy)
    else {
        while (num--) {
            *d++ = *s++;
        }
    }
    return ret;
}

三、memset函数的使用

memset 用于将内存块的每个字节设置为指定值,常用于内存初始化(如数组清零、字符串初始化等),声明在 <string.h> 头文件中。

3.1 函数原型与基本使用

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

-  ptr :目标内存块地址。
-  value :要设置的字节值(会被转换为 unsigned char )。
-  num :要设置的字节数。
- 返回值:返回 ptr 的起始地址。

示例:

#include <stdio.h>
#include <string.h>

int main() {
    int arr[5];
    // 将arr的20个字节(5个int)全部设置为0
    memset(arr, 0, 20);
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]); // 输出0 0 0 0 0
    }

    char str[10];
    // 将str的前5个字节设置为'A'(ASCII值65)
    memset(str, 'A', 5);
    str[5] = '\0'; // 手动加字符串结束符
    printf("\n%s\n", str); // 输出AAAAA
    return 0;
}

注意: memset 是按字节设置值,若用于非字符型数据(如 int ),需确保“设置值的字节重复”符合预期。例如 memset(arr, -1, 20) 会将每个字节设为 0xFF ,最终 int 值为 0xFFFFFFFF (即-1);但 memset(arr, 1, 20) 会将每个字节设为 0x01 , int 值为 0x01010101 (即16843009),而非1。

四、memcmp函数的使用


memcmp 用于按字节比较两个内存块,声明在 <string.h> 头文件中。

4.1 函数原型与基本使用

#include <stdio.h>
#include <string.h>

int main() {
    int arr1[3] = {1, 2, 3};
    int arr2[3] = {1, 2, 4};
    // 比较前8个字节(2个int,每个4字节)
    int ret = memcmp(arr1, arr2, 8);
    if (ret < 0) {
        printf("arr1前8字节 < arr2前8字节\n");
    } else if (ret > 0) {
        printf("arr1前8字节 > arr2前8字节\n");
    } else {
        printf("arr1前8字节 = arr2前8字节\n");
    }
    // 输出arr1前8字节 < arr2前8字节(因第三个int的第一个字节3<4)
    return 0;
}

五、内存函数的共性与适用场景总结

函数    核心功能 适用场景   处理重叠内存 
memcpy 内存块拷贝 非重叠内存的批量数据复制  不支持 
 memmove 增强版内存块拷贝 重叠内存的批量数据复制 支持 
memset   内存块按字节初始化 数组清零、统一赋值 (字符/字节级)  无
 memcmp 内存块按字节比较 二进制数据的逐字节对比   无


 
掌握这些内存函数,能让你在处理底层数据(如二进制文件、网络数据、复杂数据结构)时更加高效、灵活。使用时需注意内存块的空间大小和数据类型的字节长度,避免因越界或类型不匹配导致未定义行为。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐