当前位置: 首页 > java >正文

36 C 语言内存操作函数详解:memset、memcpy、memccpy、memmove、memcmp、memchr

1 memset() 函数

1.1 函数原型

#include <string.h>  // 必须包含此头文件才能使用 memsetvoid *memset(void *s, int c, size_t n);

1.2 功能说明

        memset 用于将指定内存块的前 n 个字节设置为指定的值。常用于初始化内存(如清零缓冲区或填充特定值)。

  • 参数:
    • s:指向要填充的内存块的指针
    • c:要设置的值(以 int 形式传递,但实际填充的是 unsigned char 类型,范围 0 ~ 255)
    • n:要填充的字节数
  • 返回值:
    • 返回指向 s 的指针(即目标内存块的起始地址),通常不需要显式使用返回值

1.3 注意事项

  1. 类型转换:c 参数虽然是 int 类型,但实际填充时会截断为 unsigned char(即只使用低 8 位)
  2. 性能:memset 通常由编译器或标准库高度优化,适合快速初始化大块内存
  3. 安全性:确保目标内存块的大小足够大,避免缓冲区溢出
  4. 用途限制:适合填充单字节值,不适合初始化结构体中的多字节字段(如整数或浮点数)

1.4 应用场景

        1. 内存清零:初始化数组或结构体为全 0

 // 声明一个字符数组char buf[100];// 使用 memset 将数组内存清零memset(buf, 0, sizeof(buf));// 定义一个结构体
typedef struct
{int id;char name[50];float score;
} Student;// 声明一个 Student 结构体变量Student student;// 使用 memset 将结构体内存清零memset(&student, 0, sizeof(student));

        2. 填充特定值:将缓冲区填充为特定字符(如空格或特定标记)

char str[20];
memset(str, '-', 19); // 填充 19 个 '-'
str[19] = '\0';       // 手动添加字符串结束符

        3. 重置敏感数据:在释放内存前,用 memset 清零敏感数据(如密码缓冲区)

// 在释放内存前,用 memset 清零密码缓冲区
memset(password_buffer, 0, sizeof(password_buffer));

1.5 示例程序

#include <stdio.h>
#include <string.h> // 必须包含此头文件才能使用 memsetint main()
{char buffer[10];// 初始化 buffer 为全 0memset(buffer, 0, sizeof(buffer));printf("调用 memset 后(全零): %s\n", buffer);// 填充 buffer 为 'A'memset(buffer, 'A', 9);buffer[9] = '\0'; // 添加字符串结束符printf("调用 memset 后('A'): %s\n", buffer);return 0;
}

        程序在 VS Code 中的运行结果如下所示:


2 memcpy() 函数

2.1 函数原型

#include <string.h>  // 必须包含此头文件才能使用 memcpyvoid *memcpy(void *dest, const void *src, size_t n);

2.2 功能说明

        memcpy 用于将源内存块的前 n 个字节复制到目标内存块。常用于内存数据的拷贝(如数组、结构体等)。

  • 参数:
    • dest:指向目标内存块的指针,用于存储复制的数据
    • src:指向源内存块的指针,提供要复制的数据
    • n:要复制的字节数
  • 返回值:
    • 返回指向 dest 的指针(即目标内存块的起始地址),通常不需要显式使用返回值

2.3 注意事项

  1. 内存重叠:memcpy 不处理内存重叠的情况。如果源和目标内存块有重叠,应使用 memmove 函数
  2. 性能:memcpy 通常由编译器或标准库高度优化,适合快速复制大块内存
  3. 安全性:确保目标内存块的大小足够大,避免缓冲区溢出
  4. 类型安全:确保源和目标内存块的类型兼容,避免未定义行为

2.4 应用场景

        1. 复制数组:将一个数组的内容复制到另一个数组

int src[5] = {1, 2, 3, 4, 5};
int dest[5];
memcpy(dest, src, sizeof(src)); // 复制 src 到 dest

        2. 复制结构体:将一个结构体的内容复制到另一个结构体

typedef struct
{int id;char name[20];
} Person;Person p1 = {1, "Alice"};
Person p2;
memcpy(&p2, &p1, sizeof(Person)); // 复制 p1 到 p2

        3. 缓冲区操作:在网络编程或文件操作中,复制缓冲区数据

char src_buf[100] = "Hello, world!";
char dest_buf[100];
memcpy(dest_buf, src_buf, strlen(src_buf) + 1); // 复制字符串(包括 '\0')
// strlen 返回字符串长度,不包括 '\0',所以需要加 1

2.5 示例程序

#include <stdio.h>
#include <string.h> // 必须包含此头文件才能使用 memcpy 和 strlen 函数int main()
{char src[] = "Hello, memcpy!";char dest[20];// 复制 src 到 destmemcpy(dest, src, strlen(src) + 1);// strlen(src) 返回字符串的长度,+1 是为了复制字符串的终止符 '\0'printf("复制后的字符串: %s\n", dest);// 复制部分数据int nums[5] = {1, 2, 3, 4, 5};int copied_nums[3];memcpy(copied_nums, nums, 3 * sizeof(int)); // 复制前 3 个整数printf("复制的部分数组: %d, %d, %d\n", copied_nums[0], copied_nums[1], copied_nums[2]);return 0;
}

        程序在 VS Code 中的运行结果如下所示:


3 memccpy() 函数

3.1 函数原型

#include <string.h>  // 必须包含此头文件才能使用 memccpyvoid *memccpy(void *dest, const void *src, int c, size_t n);

3.2 功能说明

        memccpy 用于将源内存块的内容复制到目标内存块,直到遇到指定的字符 c 或复制了 n 个字节为止。常用于复制字符串或内存块,直到遇到特定终止符。

  • 参数:
    • dest:指向目标内存块的指针,用于存储复制的数据
    • src:指向源内存块的指针,提供要复制的数据
    • c:要查找的终止字符(以 int 形式传递,但实际比较的是 unsigned char 类型)
    • n:要复制的最大字节数
  • 返回值:
    • 如果在复制过程中遇到字符 c,则返回指向 dest 中字符 c 之后位置的指针
    • 如果未遇到字符 c 且复制了 n 个字节,则返回 NULL

3.3 注意事项

  1. 终止字符:memccpy 会在复制过程中检查是否遇到字符 c,如果遇到则停止复制
  2. 性能:memccpy 的性能通常不如 memcpy,因为它需要额外检查字符
  3. 安全性:确保目标内存块的大小足够大,避免缓冲区溢出
  4. 类型安全:确保源和目标内存块的类型兼容,避免未定义行为

3.4 应用场景

        1. 复制字符串直到终止符:复制字符串直到遇到 \0 或指定字符

char src[] = "Hello, memccpy!";
char dest[20];
memccpy(dest, src, '!', sizeof(dest)); // 复制直到 '!' 或缓冲区满

        2. 解析特定格式的数据:从内存块中提取数据,直到遇到分隔符

char data[] = "123,456,789";
char token[10];
memccpy(token, data, ',', sizeof(token)); // 复制直到 ',' 或缓冲区满

3.5 示例程序

#include <stdio.h>
#include <string.h> // 必须包含此头文件才能使用 memccpyint main()
{char src[] = "Hello, memccpy!";char dest[20];// 复制 src 到 dest,直到遇到 '!' 或缓冲区满void *result = memccpy(dest, src, '!', sizeof(dest));if (result != NULL){printf("复制终止于 '!',结果: %s\n", dest);// 如果在复制过程中遇到字符 !,则返回指向 dest 中字符 ! 之后位置的指针printf("终止字符的下一个位置: %p \n也就是指向 dest[16] 的位置:%p\n", result, &dest[15]);}else{printf("未找到终止符 '!',复制了部分数据: %s\n", dest);}char data[] = "123,456,789";char token[10];// 复制 data 到 token,直到遇到 ',' 或缓冲区满result = memccpy(token, data, ',', sizeof(token));if (result != NULL){printf("复制终止于 ',',结果: %s\n", token);}else{printf("未找到终止符 ',',复制了部分数据: %s\n", token);}return 0;
}

        程序在 VS Code 中的运行结果如下所示:


4 memmove() 函数

4.1 函数原型

#include <string.h>  // 必须包含此头文件才能使用 memmovevoid *memmove(void *dest, const void *src, size_t n);

4.2 功能说明

        memmove 用于将源内存块的前 n 个字节复制到目标内存块。与 memcpy 不同,memmove 可以正确处理源和目标内存块重叠的情况

  • 参数:
    • dest:指向目标内存块的指针,用于存储复制的数据
    • src:指向源内存块的指针,提供要复制的数据
    • n:要复制的字节数
  • 返回值:
    • 返回指向 dest 的指针(即目标内存块的起始地址),通常不需要显式使用返回值

4.3 注意事项

  1. 内存重叠:memmove 可以正确处理源和目标内存块重叠的情况
  2. 性能:由于需要处理内存重叠,memmove 的性能通常略低于 memcpy
  3. 安全性:确保目标内存块的大小足够大,避免缓冲区溢出
  4. 类型安全:确保源和目标内存块的类型兼容,避免未定义行为

4.4 应用场景

        1. 复制重叠内存块:当源和目标内存块可能重叠时,使用 memmove 确保数据正确复制

char buffer[20] = "1234567890";
memmove(buffer + 3, buffer, 5); // 将前 5 个字符复制到从第 3 个位置开始的地方
printf("复制后的缓冲区: %s\n", buffer); // 输出: 1231234590

        2. 安全移动数据:在需要移动或调整内存数据时,使用 memmove 确保数据完整性

int nums[5] = {1, 2, 3, 4, 5};
memmove(nums + 1, nums, 3 * sizeof(int)); // 将前 3 个整数移动到从第 2 个位置开始的地方
printf("移动后的数组: %d, %d, %d, %d, %d\n", nums[0], nums[1], nums[2], nums[3], nums[4]); // 输出: 1, 1, 2, 3, 4

4.5 示例程序

#include <stdio.h>
#include <string.h> // 必须包含此头文件才能使用 memmoveint main()
{char buffer[20] = "1234567890";// 复制重叠内存块memmove(buffer + 3, buffer, 5);printf("复制后的缓冲区: %s\n", buffer); // 输出: 1231234590// 移动整数数组int nums[5] = {1, 2, 3, 4, 5};memmove(nums + 1, nums, 3 * sizeof(int));printf("移动后的数组: %d, %d, %d, %d, %d\n", nums[0], nums[1], nums[2], nums[3], nums[4]); // 输出: 1, 1, 2, 3, 5return 0;
}

        程序在 VS Code 中的运行结果如下所示:


5 memcmp() 函数

5.1 函数原型

#include <string.h>  // 必须包含此头文件才能使用 memcmpint memcmp(const void *s1, const void *s2, size_t n);

5.2 功能说明

        memcmp 用于比较两个内存块的前 n 个字节,判断它们是否相等或哪个更大。常用于比较二进制数据(如数组、结构体等)。

  • 参数:
    • s1:指向第一个内存块的指针
    • s2:指向第二个内存块的指针
    • n:要比较的字节数
  • 返回值:
    • 如果 s1 和 s2 的前 n 个字节相等,返回 0
    • 如果 s1 小于 s2(按字典序),返回负值
    • 如果 s1 大于 s2(按字典序),返回正值

5.3 注意事项

  1. 比较方式:memcmp 按字节逐个比较,比较的是内存中的二进制值,而不是字符串的逻辑值(例如,'A' 和 'a' 的 ASCII 值不同,会被认为不相等)
  2. 性能:memcmp 通常由编译器或标准库高度优化,适合快速比较大块内存
  3. 安全性:确保 s1 和 s2 指向的内存块至少有 n 个字节,避免越界访问
  4. 类型安全:memcmp 比较的是内存中的原始字节,与数据类型无关,因此适用于任何类型的内存块

5.4 应用场景

        1. 比较数组:比较两个数组的前 n 个元素是否相等

int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5] = {1, 2, 3, 4, 6};int result = memcmp(arr1, arr2, 5 * sizeof(int)); // 比较前 5 个整数if (result < 0)
{printf("arr1 小于 arr2\n");
}
else if (result > 0)
{printf("arr1 大于 arr2\n");
}
else
{printf("arr1 等于 arr2\n");
}

        2. 比较结构体:比较两个结构体的内容是否相等

typedef struct
{int id;char name[20];
} Person;Person p1 = {1, "Alice"};
Person p2 = {1, "Alice"};int result = memcmp(&p1, &p2, sizeof(Person)); // 比较两个结构体if (result == 0)
{printf("p1 等于 p2\n");
}

        3. 验证数据完整性:比较接收到的数据与预期数据是否一致

char expected[] = {0x01, 0x02, 0x03, 0x04};
char received[] = {0x01, 0x02, 0x03, 0x05};int result = memcmp(expected, received, sizeof(expected));if (result != 0)
{printf("数据不一致!\n");
}

5.5 示例程序

#include <stdio.h>
#include <string.h> // 必须包含此头文件才能使用 memcmpint main()
{// 比较数组int arr1[5] = {1, 2, 3, 4, 5};int arr2[5] = {1, 2, 3, 4, 6};// 比较前 5 个元素int result = memcmp(arr1, arr2, 5 * sizeof(int));if (result < 0){printf("arr1 小于 arr2\n");}else if (result > 0){printf("arr1 大于 arr2\n");}else{printf("arr1 等于 arr2\n");}// 比较结构体typedef struct{int id;char name[20];} Person;Person p1 = {1, "Alice"}; // 初始化结构体变量Person p2 = {1, "Alice"}; // 初始化结构体变量// 比较整个结构体result = memcmp(&p1, &p2, sizeof(Person));if (result == 0){printf("p1 等于 p2\n");}// 比较字符串(注意:memcmp 比较的是二进制值)char str1[] = "Hello";char str2[] = "hello";/*'H' (0x48,二进制 01001000) 和 'h' (0x68,二进制 01101000)。0x48('H')的二进制值小于 0x68('h'),因此 memcmp 会立即返回一个负值,表示 "Hello" 的第一个字节小于 "hello" 的第一个字节。*/result = memcmp(str1, str2, 5); // 比较前 5 个字符if (result < 0){printf("str1 小于 str2(按二进制值比较)\n");}return 0;
}

        程序在 VS Code 中的运行结果如下所示:


6 memchr() 函数

6.1 函数原型

#include <string.h>  // 必须包含此头文件才能使用 memchrvoid *memchr(const void *s, int c, size_t n);

6.2 功能说明

        memchr 用于在内存块的前 n 个字节中搜索特定字节值的首次出现位置。它逐字节扫描内存块,直到找到匹配的字节或扫描完指定的字节数 n。

  • 参数:
    • s:指向要搜索的内存块的指针
    • c:要搜索的字节值(以 int 形式传递,但实际比较的是 unsigned char 类型,范围 0 ~ 255)
    • n:要搜索的字节数
  • 返回值:
    • 如果找到匹配的字节,返回指向该位置的指针
    • 如果未找到匹配的字节,返回 NULL

6.3 注意事项

  1. 类型转换:c 参数虽然是 int 类型,但实际比较时会转换为 unsigned char
  2. 性能:memchr 通常由编译器或标准库高度优化,适合快速搜索大块内存
  3. 安全性:确保搜索范围不超过目标内存块的实际大小,避免越界访问
  4. 大小写敏感:搜索是区分大小写的,'A' 和 'a' 会被视为不同的值

6.4 应用场景

        1. 查找特定字符:在字符串或缓冲区中查找特定字符的位置

char text[] = "Programming in C";
char *found = memchr(text, 'a', strlen(text));if (found)
{printf("找到字符 'a',位置在: %lld\n", found - text);
}
else
{printf("未找到字符 'a'\n");
}

        2. 检查二进制数据中是否存在特定标记

unsigned char data[] = {0x01, 0x02, 0xFF, 0x03};if (memchr(data, 0xFF, sizeof(data)))
{printf("数据中包含 0xFF 标记\n");
}

        3. 快速定位缓冲区中的分隔符

char buffer[] = "data1,data2,data3";
char *sep = memchr(buffer, ',', strlen(buffer));if (sep)
{printf("找到分隔符 ',' 在位置: %lld\n", sep - buffer);
}

6.5 示例程序

#include <stdio.h>
#include <string.h> // 必须包含此头文件才能使用 memchrint main()
{char str[] = "This is a sample string for memchr demonstration";// 查找空格字符 ' 'char *space_pos = memchr(str, ' ', strlen(str));if (space_pos){printf("找到空格字符,位置在: %lld\n", space_pos - str);printf("找到的字符是: '%c'\n", *space_pos);}else{printf("未找到空格字符\n");}// 查找字母 'm'char *m_pos = memchr(str, 'm', strlen(str));if (m_pos){printf("找到字母 'm',位置在: %lld\n", m_pos - str);printf("找到的字符是: '%c'\n", *m_pos);}else{printf("未找到字母 'm'\n");}// 查找不存在的字符 'X'char *x_pos = memchr(str, 'X', strlen(str));if (!x_pos){printf("未找到字符 'X'\n");}return 0;
}

        程序在 VS Code 中的运行结果如下所示:


7 内存操作函数总结

函数名功能描述参数返回值
memset将内存块的所有字节设置为指定值

void *s(目标内存块指针),

int c(要设置的值),

size_t n(要设置的字节数)

返回目标内存块的指针
memcpy从源内存块复制字节到目标内存块

void *dest(目标内存块指针),

const void *src(源内存块指针),

size_t n(复制的字节数)

返回目标内存块的指针
memccpy从源内存块复制字节到目标内存块,直到遇到指定字符或复制了指定字节数

void *dest(目标内存块指针),

const void *src(源内存块指针),

int c(要查找的字符),

size_t n(复制的字节数)

遇到字符时返回指向目标内存块中该字符之后位置的指针,否则返回 NULL
memmove从源内存块复制字节到目标内存块,正确处理内存重叠

void *dest(目标内存块指针),

const void *src(源内存块指针),

size_t n(复制的字节数)

返回目标内存块的指针
memcmp比较两个内存块的内容

const void *s1(第一个内存块指针),

const void *s2(第二个内存块指针),

size_t n(比较的字节数)

如果 s1 小于、等于或大于 s2,分别返回负整数、零或正整数
memchr在内存块中搜索特定字节值的首次出现位置

const void *s(目标内存块指针),

int c(要搜索的字节值),

size_t n(扫描的字节数)

找到时返回指向该字节的指针,否则返回 NULL

其他类似但非标准 C 库的函数:

  • bcmp:类似于 memcmp,用于比较两个内存块的内容,但通常不是标准 C 库的一部分。
  • bcopy:类似于 memcpy 或 memmove,用于复制内存块,但通常不是标准 C 库的一部分。
  • bzero:类似于 memset,用于将内存块的所有字节设置为 0,但通常不是标准 C 库的一部分。
  • memicmp:类似于 memcmp,但不区分大小写,通常不是标准 C 库的一部分。
  • movmem:类似于 memmove,用于复制内存块,可能包含额外的功能或优化,通常不是标准 C 库的一部分。
  • setmem:类似于 memset,用于将内存块的所有字节设置为指定值,可能包含额外的功能或优化,通常不是标准 C 库的一部分。
http://www.xdnf.cn/news/12759.html

相关文章:

  • 开启二进制日志 MySQL显示关闭,关闭二进制日志 MySQL恢复正常
  • 全球人工智能技术大会(GAITC 2025):技术前沿与产业融合的深度交响
  • Prompt工程学习之思维树(TOT)
  • C++课设:从零开始打造影院订票系统
  • .net 可以调试的Windows服务框架Topshelf
  • ClickHouse 25.3 json列类型使用示例
  • 基于自适应虚拟谐波阬的光储VSG并网电流谐波抑制模型
  • 归并排序:分治思想的高效排序
  • UDP 与 TCP 的区别是什么?
  • CppCon 2015 学习:Memory and C++ debugging at Electronic Arts
  • day6 cpp:c中处理字符串,c++string
  • 第二十周:Redis(二)
  • 条件语句易错点
  • Android 集成 Firebase 指南
  • 如何写一篇基于Spring Boot + Vue + 微信小程序的软件的接口文档
  • Tavily 技术详解:为大模型提供实时搜索增强的利器
  • 行为设计模式之Iterator(迭代器)
  • Ubuntu20.04中MySQL的安装和配置
  • 【iOS】JSONModel源码学习
  • LLMs 系列科普文(8)
  • 多线程语音识别工具
  • 【工具教程】多个条形码识别用条码内容对图片重命名,批量PDF条形码识别后用条码内容批量改名,使用教程及注意事项
  • 告别 @MockBean!在 Spring Boot 3.2+ 中使用 @MockitoBean 进行单元测试
  • 智慧园区管理平台
  • 阿里云Alibaba Cloud安装Docker与Docker compose【图文教程】
  • Spring 中的三级缓存机制详解
  • MySQL索引:7大类型+4维分类
  • 《Windows 10下QT+OpenCV+Yolo11:AI视觉开发实战指南》
  • GNSS高精度定位之-----星基差分
  • 数据网格的革命:从集中式到分布式的数据管理新范式