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 的方向处理。

相关推荐
Elastic 中国社区官方博客6 小时前
使用 Lucene 搜索你的 Bean —— Elasticsearch
大数据·开发语言·人工智能·elasticsearch·搜索引擎·全文检索·lucene
Sayai6 小时前
Neo4j 内嵌模式(Embedded)实战:Java 嵌入式 vs 服务端部署的写入性能对比与 GC 调优
java·开发语言·性能优化·neo4j·图数据库
“AI国潮设计-小江”7 小时前
【SDXL实战】用AI生成“财神爷蛋糕×英歌舞人物”潮汕国潮甜品IP,附Prompt与批量生成思路
开发语言·人工智能·python·aigc
繁华的地方不一定留下你的脚印7 小时前
C++线程如何安全停止与唤醒:std::jthread、stop_token与condition_variable
开发语言·c++
Navigator_Z7 小时前
LeetCode //C - 1269. Number of Ways to Stay in the Same Place After Some Steps
c语言·算法·leetcode
caoerzhong7 小时前
跨境海外仓怎么管:JeeWMS 开源 Java 仓库管理系统打通头程、海外仓与尾程
java·开发语言·开源
码云数智-大飞7 小时前
新手写 Python 代码,如何规范命名、减少 Bug
开发语言·python·php
福兮说7 小时前
JS 正则的六个坑:带 g 的 test() 一真一假、空匹配死循环、replace 里的 $
开发语言·前端·javascript·正则表达式
码艺-Alimjan8 小时前
Web 网站打包桌面应用的另一种方式,超级简单(C# exe 33Kb)
开发语言·前端·c#
沫璃染墨8 小时前
《从零入门Linux系统篇(五十一):线程篇·四——pthread线程库详解:从线程创建到终止与分离》
linux·运维·服务器·开发语言·c++·系统架构·线程