C语言内存函数完全指南:memcpy/memmove/memset/memcmp

C语言内存函数完全指南:memcpy/memmove/memset/memcmp

除了字符串操作,C标准库还提供了一系列直接操作内存块的函数。这些函数以字节为单位处理数据,能够高效地拷贝、移动、设置和比较任意类型的内存块。本文将详细讲解 memcpy、memmove、memset、memcmp 的用法、区别及模拟实现,帮助读者安全灵活地操纵内存。

目录


一、memcpy的使用和模拟实现

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

  • 从 source 位置向后复制 num 个字节到 destination。
  • 不会因为遇到 '\0' 而停止,完全按字节数操作。
  • 如果源和目标内存区域重叠 ,行为未定义(应使用 memmove)。

示例:拷贝整型数组的前5个元素(20字节)

c 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    int arr1[] = {1,2,3,4,5,6,7,8,9,10};
    int arr2[10] = {0};
    memcpy(arr2, arr1, 20);   // 拷贝20字节(5个int)
    for (int i = 0; i < 10; i++)
        printf("%d ", arr2[i]); // 1 2 3 4 5 0 0 0 0 0
    return 0;
}

模拟实现:

c 复制代码
void *my_memcpy(void *dst, const void *src, size_t count) {
    void *ret = dst;
    assert(dst && src);
    while (count--) {
        *(char*)dst = *(char*)src;
        dst = (char*)dst + 1;
        src = (char*)src + 1;
    }
    return ret;
}

关键 :使用 char* 指针逐字节拷贝,保证通用性。


二、memmove的使用和模拟实现

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

  • 功能与 memcpy 类似,但允许源和目标内存重叠。
  • 当无法确定是否重叠时,应优先使用 memmove。

示例:将数组前5个元素移动到从下标2开始的位置

c 复制代码
int arr[] = {1,2,3,4,5,6,7,8,9,10};
memmove(arr+2, arr, 20);  // 重叠拷贝
// 结果:1 2 1 2 3 4 5 8 9 10

模拟实现(需考虑拷贝方向):

  • 若目标地址在源地址之前,从前往后拷贝。
  • 若目标地址在源地址之后且重叠,从后往前拷贝。
c 复制代码
void *my_memmove(void *dst, const void *src, size_t count) {
    void *ret = dst;
    assert(dst && src);
    if (dst <= src || (char*)dst >= (char*)src + count) {
        // 非重叠或目标在前:从前向后拷贝
        while (count--) {
            *(char*)dst = *(char*)src;
            dst = (char*)dst + 1;
            src = (char*)src + 1;
        }
    } else {
        // 重叠且目标在后:从后向前拷贝
        dst = (char*)dst + count - 1;
        src = (char*)src + count - 1;
        while (count--) {
            *(char*)dst = *(char*)src;
            dst = (char*)dst - 1;
            src = (char*)src - 1;
        }
    }
    return ret;
}

三、memset函数的使用

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

  • 将 ptr 指向的内存块的前 num 个字节每个字节 设置为 value(value 转为 unsigned char 后填充)。
  • 常用于数组或结构体的快速初始化。

示例 :将字符串前6个字符改为 'x'

c 复制代码
char str[] = "hello world";
memset(str, 'x', 6);
printf("%s\n", str);  // "xxxxx world"

注意 :memset 以字节为单位,不能用于将整型数组全部设为 1(因为会变成 0x01010101),除非值为 0。

c 复制代码
int arr[10];
memset(arr, 0, sizeof(arr));   // 正确,全部置0
memset(arr, 1, sizeof(arr));   // 每个字节变1,整型值变为 0x01010101

四、memcmp函数的使用

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

  • 比较 ptr1 和 ptr2 指向的内存块的前 num 个字节。
  • 返回值与 strcmp 类似:
    • <0:ptr1 的字节值小于 ptr2
    • 0:相等
    • >0:ptr1 的字节值大于 ptr2

示例:比较两个字符串(区分大小写)

c 复制代码
char buf1[] = "DWgaOtP12df0";
char buf2[] = "DWGAOTP12DF0";
int n = memcmp(buf1, buf2, sizeof(buf1));
if (n > 0)
    printf("%s is greater than %s\n", buf1, buf2);
else if (n < 0)
    printf("%s is less than %s\n", buf1, buf2);
else
    printf("equal\n");

注意 :memcmp 比较的是原始字节值(按 unsigned char 比较),而不是字符串语义,不会因为 '\0' 提前停止。


总结:内存函数以字节为单位操作内存,适用于任何数据类型。memcpy 高效但不能重叠拷贝;memmove 支持重叠,更安全;memset 快速填充字节;memcmp 比较内存块。掌握这些函数并理解其模拟实现,能够有效处理数组、结构体等内存块,提升代码性能和可靠性。特别注意 memset 的字节填充特性及 memmove 的方向处理。

相关推荐
Pniubi2 小时前
HashMap的扩容和树化边界
java·开发语言
gCode Teacher 格码致知4 小时前
Pandas教学-17:Series与Dataframe的关系
开发语言·python·pandas
发量惊人的中年网工4 小时前
分公司访问总部ERP慢怎么办?SD-WAN组网的排查与验收要点
服务器·开发语言·php
下页、再停留4 小时前
【C#桌面客户端系列学习-15】生成可视化图表之折线图、柱状图、饼状图
开发语言·c#
ShineWinsu4 小时前
对于JavaScript:操作元素的解析
开发语言·前端·javascript·面试·web·dom·元素
益莱储中国6 小时前
深度解析:RF 实验室从 5G迈向 6G 的过程中保持技术领先与设备升级的路径
开发语言·php
benchmark_cc7 小时前
Python 量化系统如何设计统一的数据访问接口:从策略解耦到数据层架构
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
const_qiu7 小时前
第四章 00:开篇 —— 从「会聊天」到「记得住、会干活、能协作」
java·开发语言·人工智能·python
Wang's Blog7 小时前
Java 项目实战: 交友项目 - 个人资料管理的更新接口实现与坑
java·开发语言·交友
CoderYanger7 小时前
Java EE 进阶:4.Spring Web MVC 入门(第一弹)
java·开发语言·前端·spring·面试·java-ee·mvc