自己实现内存赋值函数memset 2020-10-21

#include <stdio.h>
//#include <stdlib.h>
void *my_memset(void *a, int b, size_t n)
{
    assert(a != NULL);
    char *t = (char*)a;
    while(n--)
    {
        t[n] = (char)b;
    }
    return a;
}
int main ()
{
    char str1 = {"hello"};
    printf("my memset %s\n", my_memset(str1, 'a', 3));  //aaalo
    return 0;
}

void bzero(void *s, size_t n)将s开始的n个字节赋值为0;

<think>好的,用户让我介绍一下内存操作函数memset。首先,我需要回忆一下memset的基本用途和功能。记得它是C语言中的一个库函数,主要用于设置内存块的值。通常在头文件<string.h>里声明,对吧?那它的函数原型应该是void *memset(void *ptr, int value, size_t num),其中ptr指向要填充的内存块,value是要设置的值,num是要设置的字节数。 接下来,我需要考虑用户可能的背景。可能是刚开始学编程的学生,或者在使用memset时遇到问题的人。他们可能想知道为什么用这个函数,或者常见的使用场景,比如初始化数组、结构体清零等。同时,用户可能对参数的理解有疑问,比如value虽然是int类型,但实际上会被转换为unsigned char处理,这点需要强调清楚。 然后,常见的错误和注意事项也是重点。比如,误用memset初始化非字符数组,尤其是当数组元素类型不是单字节的时候,可能导致错误。例如,用memset(arr, 1, sizeof(arr))来初始化int数组,每个int的四个字节都会被设为0x01,但实际的值会是0x01010101,而不是1。这个例子很重要,需要具体说明。 还有,结构体清零的正确用法,比如用memset(&obj, 0, sizeof(obj))来快速清零内存,但如果有指针成员的话,可能会有隐患。不过用户可能更关心基础用法,所以先讲基本点,再提注意事项。 另外,性能方面,memset通常由底层优化,处理大块内存时效率高,这也是它的优势之一。需要提到这点,让用户了解在适当场合使用。 可能需要举例说明正确的使用方式,比如初始化字符数组为全0,或者设置特定模式的内存块。同时,提醒用户注意第三个参数是字节数,不要忘记乘以sizeof(type),尤其是对于非字符类型的数组。 最后,总结memset的适用场景和常见陷阱,帮助用户正确使用。确保回答结构清晰,分点说明,用例子辅助理解,避免过于技术化的术语,保持口语化但准确。</think>我来帮你逐步理解内存操作函数 `memset` 的作用和用法: #### 一、基础概念 `memset` 是 C 语言标准库中的内存操作函数,定义在 `<string.h>` 头文件中。它的核心功能是 **以字节为单位批量设置内存块的值**。 #### 二、函数原型 ```c void *memset(void *ptr, int value, size_t num); ``` - `ptr`: 指向要操作的内存块的指针 - `value`: 要设置的字节值(实际会被转换为 `unsigned char`) - `num`: 要设置的字节数量 - **返回值**:返回原始 `ptr` 指针 #### 三、典型应用场景 1. **初始化内存清零** ```c int arr[10]; memset(arr, 0, sizeof(arr)); // 将数组所有字节设为0 ``` 2. **设置特定模式** ```c char buffer[1024]; memset(buffer, 0xFF, 1024); // 将所有字节设为0xFF ``` 3. **结构体初始化** ```c struct Student { int id; char name[20]; }; struct Student s; memset(&s, 0, sizeof(s)); // 清空结构体 ``` #### 四、关键注意事项 1. **字节级操作特性** ```c int nums[5]; memset(nums, 1, sizeof(nums)); // 错误用法! ``` 每个 `int` 的 4 字节会被设为 `0x01`,最终每个 `int` 值变为 `0x01010101`(十进制为 16843009),而非期望的 1 2. **正确清零结构体** ```c struct Data { int a; double b; }; struct Data d; memset(&d, 0, sizeof(d)); // 正确清零所有成员 ``` 3. **性能优势** 相比循环赋值,`memset` 使用底层优化指令(如 x86 的 `REP STOSB`),处理大内存块时效率更高 #### 五、等效代码解析 假设要实现简化版 `memset`: ```c void *my_memset(void *s, int c, size_t n) { unsigned char *p = s; while(n-- > 0) { *p++ = (unsigned char)c; } return s; } ``` 这个实现清晰地展示了逐字节设置内存的过程 #### 六、特殊用法示例 设置内存对齐的标记位: ```c #define ALIGNMENT 16 void *allocate_aligned(size_t size) { void *ptr = malloc(size + ALIGNMENT); if (!ptr) return NULL; uintptr_t addr = (uintptr_t)ptr; size_t offset = ALIGNMENT - (addr % ALIGNMENT); memset((char*)ptr + offset - 1, 0xAA, 1); // 设置对齐标记 return (char*)ptr + offset; } ``` #### 七、常见错误排查 错误现象:程序出现随机内存错误 可能原因: ```c int *arr = malloc(10 * sizeof(int)); memset(arr, 0, 10); // 错误!应写10*sizeof(int) ``` 正确写法: ```c memset(arr, 0, 10 * sizeof(int)); // 设置40字节(假设int为4字节) ``` 理解 `memset` 的关键是记住它进行的是 **字节级操作**,使用时需特别注意目标内存的类型和长度。在需要按字节模式初始化内存的场景下,这个函数非常高效实用,但误用也容易造成隐蔽的错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值