C/C++---memset()初始化

memset 是 C/C++ 标准库中用于内存块初始化的函数,定义在 <cstring> 头文件中。它的核心功能是将一块连续内存的每个字节都设置为指定的值,常用于初始化数组、结构体等数据结构。

一、函数原型

cpp 复制代码
void* memset(void* ptr, int value, size_t num);
  • 参数说明
    • ptr:指向要初始化的内存块的起始地址(必须是可修改的内存,如数组、动态分配的内存等)。
    • value:要设置的值(虽然类型是 int,但实际只会使用其低 8 位,即 unsigned char 范围内的值)。
    • num:要设置的字节数(size_t 类型,通常是内存块的总大小)。
  • 返回值 :返回指向内存块起始地址的指针(即 ptr)。

二、工作原理

memset 会从 ptr 指向的地址开始,逐个字节地将内存设置为 value 的低 8 位。例如:

cpp 复制代码
int arr[5];
memset(arr, 0, sizeof(arr));  // 将arr的每个字节都设为0
  • sizeof(arr) 计算数组总字节数(5 * 4 = 20 字节,假设 int 为 4 字节)。
  • memset 会将这 20 个字节全部设置为 0x00,最终数组每个元素都为 0

三、使用场景

  1. 初始化数组为 0 或 -1

    最常见的用法是将数组初始化为全 0 或全 -1(因二进制特性,见下文注意事项):

    cpp 复制代码
    int a[100];
    memset(a, 0, 100 * sizeof(int));  // 全0初始化
    
    char str[20];
    memset(str, '\0', 20);  // 字符串结束符初始化(等价于0)
  2. 清空结构体/缓冲区

    用于重置结构体或内存缓冲区的内容:

    cpp 复制代码
    struct Student {
        int id;
        char name[20];
    };
    Student s;
    memset(&s, 0, sizeof(Student));  // 结构体成员全设为0
  3. 快速填充字符数组

    对字符数组(每个元素占 1 字节)可直接填充指定字符:

    cpp 复制代码
    char buf[10];
    memset(buf, 'a', 10);  // 数组元素全为 'a'(ASCII码97)

四、关键注意事项

  1. 按字节赋值的局限性
    memset逐字节设置的,因此仅适用于以下情况:

    • 目标类型为单字节类型(如 charunsigned char)。
    • 希望将多字节类型(如 intlong)的每个字节都设为相同值(如 0 或 -1)。

    ❌ 错误示例(对 int 数组填充非 0/-1 的值):

    cpp 复制代码
    int arr[3];
    memset(arr, 1, 3 * sizeof(int));  // 错误!结果不是 [1,1,1]

    原因:int 占 4 字节,memset 会将每个字节设为 0x01,实际每个元素为 0x01010101(十进制 16843009),而非 1。

  2. value 参数的有效范围

    虽然 value 类型是 int,但实际只使用低 8 位(0~255-128~127)。例如:

    cpp 复制代码
    memset(ptr, 256, num);  // 等价于 memset(ptr, 0, num)(256的低8位为0)
    memset(ptr, -1, num);   // 等价于填充 0xFF(因-1的二进制补码为全1)
  3. 避免越界访问
    num 参数必须小于等于 ptr 指向的内存块大小,否则会导致缓冲区溢出,引发未定义行为(如程序崩溃、数据损坏)。

  4. std::fill 的区别

    C++ 中的 std::fill 是更通用的初始化工具,按元素赋值而非按字节,适用于任何类型:

    cpp 复制代码
    #include <algorithm>  // 需包含此头文件
    int arr[3];
    std::fill(arr, arr + 3, 1);  // 正确将每个元素设为1(按int类型赋值)
    • memset 速度更快(底层优化),但适用场景有限。
    • std::fill 更灵活,支持任意值初始化,但性能略低。

五、常见错误用法

  1. 对非字节类型填充任意值(如上述 int 数组填充 1)。

  2. 错误计算 num 大小(如用元素个数代替字节数):

    cpp 复制代码
    int arr[10];
    memset(arr, 0, 10);  // 错误!仅初始化前10字节(不足3个int元素)
  3. 对只读内存(如字符串常量)使用 memset

    cpp 复制代码
    char* str = "hello";
    memset(str, 'a', 5);  // 错误!字符串常量不可修改,会导致崩溃

memset 是高效的内存初始化工具,核心作用是按字节批量设置内存值,但需注意:

  • 仅适用于单字节类型或多字节类型的全 0/-1 初始化。
  • 严格控制 num 参数,避免越界。
  • 复杂类型的初始化优先考虑 std::fill 等更安全的方法。