memset函数总结

之前有一个程序栽在了memset函数上面,对memset函数一直耿耿于怀,于是想总结一下这个常用但是总出错的函数。

memset在string.h文件中是这么定义的:


void*代表这个函数的返回值可以是任意类型的指针。

_cdecl是C Declaration的缩写,表示C语言默认的函数调用方法。该方法具体为:所有参数从左到右依次入栈,这些参数由调用者清除,称为手动清栈。被调用函数不会调用调用者传递多少参数,调用者传递过多或过少的参数,甚至完全不同的参数都不会产生编译阶段的错误(转自百度百科)。

紫色部分_Out_writes_bytes_all_与 _In_是微软的源代码注释。

第一个参数是任意类型的指针。第二个参数是所赋的值。第三个参数是字节大小。

整个函数的含义就是将_Dst中的前_Size多的字节赋值为_Val,并返回修改后的_Dst。

这里要注意:memset函数中的_size是以字节为单位的。举例:

#include <iostream>
#include <cstring>
using namespace std;

int main()
{
	char a[5];
	memset(a,'v',5);

	cout<<a[0]<<endl;
	cout<<a[1]<<endl;
	cout<<a[2]<<endl;
	cout<<a[3]<<endl;
	cout<<a[4]<<endl;

	system("pause");
	return 0;
}

结果:


memset(a,'v',5);这里的第三个参数直接是5,没有给任何单位,就可以成功将char a[5]成功赋值说明memset是对字符型操作的。

所以说这样的情况

#include <iostream>
#include <cstring>
using namespace std;

int main()
{
	int a[5];
	memset(a,10,5);

	cout<<a[0]<<endl;
	cout<<a[1]<<endl;
	cout<<a[2]<<endl;
	cout<<a[3]<<endl;
	cout<<a[4]<<endl;

	system("pause");
	return 0;
}

就会出现这样的情况:


那这样呢

#include <iostream>
#include <cstring>
using namespace std;

int main()
{
	int a[5];
	memset(a,10,5*sizeof(int));

	cout<<a[0]<<endl;
	cout<<a[1]<<endl;
	cout<<a[2]<<endl;
	cout<<a[3]<<endl;
	cout<<a[4]<<endl;

	system("pause");
	return 0;
}

还是不对:



然后我就思考一下为什么,觉得应该是这样

看第一个实例memset(a,10,5)。因为memset是以字节为单位的,所以其含义就是int a[5]。以地址a起始,5个字节都要赋值为10。

这样的话,a[0]=0x0A0A0A0A,即为168430090

a[1]=0xXXXXXX0A

a[2]没赋值

a[3]没赋值

a[4]没赋值

a[5]没赋值。所以会出现上面的情况。

 

而第二个例子memset(a,10,5*sizeof(int))。

无非还是以字节为单位赋值了20个字节,

a[0]=0x0A0A0A0A

a[1]=0x0A0A0A0A

a[2]=0x0A0A0A0A

a[3]=0x0A0A0A0A

a[4]=0x0A0A0A0A,出现的结果即都是168430090。

所以说,我觉得除了char数组,其余的(比方说struct,int[])用memset函数均需要小心谨慎,今天写一个程序就栽在这里了,特地写一篇总结。但后来发现memset函数还有成功的时候,就是

int a[10];

memset(a,0,10*sizeof(int));

哈哈,原理自不必说了。


版权声明:本文为博主原创文章,未经博主允许不得转载。

转载于:https://www.cnblogs.com/lightspeedsmallson/p/4785910.html

<think>好的,用户之前问过关于sprintf函数的问题,现在又问到了memset和相关函数。我需要先理解用户的需求。用户可能是在学习C或C++中的内存操作函数,或者是想了解如何安全地操作内存。 首先,memset是用于设置内存块的内容,通常用来初始化为某个值,比如清零或者填充特定字符。但用户可能不知道它的陷阱,比如不能用于初始化非字符类型的数组到0以外的值,这可能会导致未定义行为。需要强调这一点,避免用户错误使用。 然后,用户提到了“相关函数”,可能指的是其他内存操作函数,比如memcpy、memmove、memcmp、memchr等。需要逐一解释每个函数的作用、参数、返回值以及使用场景,同时指出它们的区别,比如memcpy和memmove在处理内存重叠时的不同。 接下来,用户可能关心这些函数的安全性问题,比如缓冲区溢出。可以提到安全增强版本,如memset_s,或者C++中的替代方法,比如使用容器或智能指针来避免手动内存管理带来的风险。 用户可能是在进行底层编程,比如处理数据结构、网络协议或加密算法,这些场景下经常需要操作内存。因此,实际应用示例会很有帮助,比如清零结构体、复制数据块、比较内存内容等。 另外,需要比较不同函数的区别,比如memcpy和memmove的区别,这样用户在实际使用中能正确选择。还要注意平台兼容性问题,比如某些安全函数只在特定标准或编译器中可用。 最后,总结使用建议,强调安全性,推荐使用更安全的函数C++的替代方法,避免常见错误。可能用户之前在使用sprintf时已经遇到过缓冲区溢出的问题,所以对于memset和相关函数,也需要提醒类似的安全隐患,并提供解决方案。</think>`memset` 是 C/C++ 中用于**内存块初始化**的基础函数,常与其他内存操作函数(如 `memcpy`、`memmove` 等)配合使用。以下是详细介绍: --- ### **`memset` 函数** #### **功能** 将一块内存的每个字节设置为指定值(按字节填充)。 #### **函数原型** ```c void* memset(void* ptr, int value, size_t num); ``` - **`ptr`**:目标内存的起始地址。 - **`value`**:要设置的字节值(范围 `0~255`,超出时取低8位)。 - **`num`**:要设置的字节数。 - **返回值**:返回 `ptr` 的原始地址。 #### **典型用途** 1. **初始化内存为0** ```c int arr[100]; memset(arr, 0, sizeof(arr)); // 将整块内存清零 ``` 2. **填充特定字符** ```c char buffer[50]; memset(buffer, &#39;A&#39;, 10); // 前10字节填充字符&#39;A&#39; ``` #### **注意事项** - **仅按字节填充**:无法直接初始化非字符类型(如 `int`、`float`)为特定数值(如 `1`),因为逐字节填充可能导致非预期值。 ```c int arr[5]; memset(arr, 1, sizeof(arr)); // 每个int的每个字节为0x01,但int值可能非1! ``` - **安全风险**:不检查目标内存是否有效或足够大,需自行保证内存合法性。 --- ### **相关内存操作函数** #### **1. `memcpy`** - **功能**:将一块内存的内容复制到另一块内存(不处理内存重叠)。 - **原型**: ```c void* memcpy(void* dest, const void* src, size_t num); ``` - **示例**: ```c char src[] = "Hello"; char dest[10]; memcpy(dest, src, 6); // 复制包括结尾的&#39;\0&#39; ``` - **注意**:若 `dest` 和 `src` 内存重叠,行为未定义(需用 `memmove`)。 #### **2. `memmove`** - **功能**:安全复制内存,允许源和目标内存重叠。 - **原型**: ```c void* memmove(void* dest, const void* src, size_t num); ``` - **示例**: ```c char str[] = "ABCDEF"; memmove(str + 2, str, 4); // 结果为 "ABABCF" ``` #### **3. `memcmp`** - **功能**:比较两块内存的内容是否相同。 - **原型**: ```c int memcmp(const void* ptr1, const void* ptr2, size_t num); ``` - **返回值**: - `<0`:`ptr1` 小于 `ptr2`(按字节比较)。 - `=0`:两块内存内容相同。 - `>0`:`ptr1` 大于 `ptr2`。 - **示例**: ```c int a[3] = {1, 2, 3}; int b[3] = {1, 2, 3}; if (memcmp(a, b, sizeof(a)) == 0) { // 内存内容相同 } ``` #### **4. `memchr`** - **功能**:在内存块中搜索指定字节值。 - **原型**: ```c void* memchr(const void* ptr, int value, size_t num); ``` - **示例**: ```c char data[] = "Hello"; char* pos = memchr(data, &#39;l&#39;, 5); // 找到第一个&#39;l&#39;的位置 ``` --- ### **安全增强版本(C11/C++)** - **`memset_s`**:C11 引入的安全版本,可检测缓冲区溢出(需支持 Annex K)。 ```c errno_t memset_s(void* dest, rsize_t destsz, int value, rsize_t count); ``` - **C++ 替代**: - 使用 `std::fill` 或容器(如 `std::vector`)的 `assign` 方法。 ```cpp std::vector<int> vec(100); std::fill(vec.begin(), vec.end(), 0); // 安全初始化 ``` --- ### **实际应用场景** 1. **清零敏感数据** ```c char password[100]; // 使用后立即清空内存防止泄露 memset(password, 0, sizeof(password)); ``` 2. **结构体初始化** ```c typedef struct { int id; char name[20]; } Person; Person p; memset(&p, 0, sizeof(Person)); // 清零结构体 ``` 3. **位图操作** ```c unsigned char bitmap[1024]; memset(bitmap, 0xFF, sizeof(bitmap)); // 所有位设为1 ``` --- ### **常见错误** 1. **误用字节填充数值类型** ```c int* arr = malloc(10 * sizeof(int)); memset(arr, 1, 10 * sizeof(int)); // 错误!每个int的值非1,而是0x01010101 ``` 2. **内存越界** ```c char buffer[5]; memset(buffer, 0, 10); // 越界写入,导致未定义行为 ``` 3. **忽略内存重叠** ```c char str[] = "12345"; memcpy(str + 1, str, 4); // 错误!内存重叠应用memmove ``` --- ### **总结** - **`memset`**:快速初始化内存,适合清零或填充字节模式。 - **`memcpy/memmove`**:内存复制,后者支持重叠区域。 - **`memcmp/memchr`**:内存比较与搜索。 - **安全建议**:优先使用 `memset_s`(C)或 C++ 容器,避免手动内存操作风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值