使用ZeroMemory、memset对结构体、数组的初始化

1、使用memset初始化:

memset函数原型:void * memset(void *ptr,int value,size_t num);  作用:用于为地址ptr开始的num个字节赋值value

typedef struct s1
{
	SOCKET		m_Socket;
	SOCKADDR_IN m_ClientAddr;
 
	//初始化
	s1()
	{
		m_Socket = INVALID_SOCKET;
		//SOCKADDR_IN本身也是个结构体可以使用memset方法初始化
		memset(&m_ClientAddr, 0, sizeof(m_ClientAddr));
	}
};
 
struct Stu
{
	int nNum;
	bool bSex;
	char szName[20];
	char szEmail[100];
 
	//这样初始化也可以
	Stu()
	{
		memset(this, 0, sizeof(Stu));
 
		//或者下面的格式
		//memset(&nNum, 0, sizeof(Stu));
	}
};

2、

使用ZeroMemory的初始化

ZeroMemory只有将数据置零的功能,在windows平台下,数组或纯结构使用ZeroMemory是安全的

typedef struct _PER_IO_CONTEXT
{
	OVERLAPPED		m_Overlapped;	//每一个重叠网络操作的重叠结构(针对每一个Socket的每一个操作,都要有一个)
	SOCKET			m_sockAccept;	//这个网络操作所使用的Socket
	WSABUF			m_wsaBuf;		//WSA类型的缓冲区,用于给重叠操作传参数
	char			m_szBuffer[MAX_BUFFER_LEN]; //WSABUF里具体存字符的缓冲区
	OPERATION_TYPE	m_OpType;		//标识网络操作的类型
 
	//初始化
	_PER_IO_CONTEXT()
	{
		ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
		ZeroMemory(m_szBuffer, MAX_BUFFER_LEN);
		m_sockAccept = INVALID_SOCKET;
		m_wsaBuf.buf = m_szBuffer;
		m_wsaBuf.len = MAX_BUFFER_LEN;
		m_OpType = NULL_POSTED;
	}
 
	//释放掉Socket
	~_PER_IO_CONTEXT()
	{
		if (m_sockAccept != INVALID_SOCKET)
		{
			closesocket(m_sockAccept);
			m_sockAccept = INVALID_SOCKET;
		}
	}
 
	//重置缓冲区内容
	void ResetBuffer()
	{
		ZeroMemory(m_szBuffer, MAX_BUFFER_LEN);
	}
}PER_IO_CONTEXT,*PPER_IO_CONTEXT;

3、注意事项:

(1)  不能认为memset可以赋值为任意的值,因为memset函数在赋值时是逐个字节赋值的,如果是一个int类型的数组,比如int a[10];其中每个元素占有4字节的大小,如果执行memset(a,1,sizeof(a));则此时并不是将数组里面所有值都赋值为1,而是将每个元素的4个字节分别赋值为1,则其二进制大小为0000 0001 0000 0001 0000 0001 0000 0001,也就是将4组值为1的二进制连接起来,所以此时数组中每个元素大小为16843009,与其预期不符,但是可以使用0或者-1为int类型数组赋值,因为0对应的二进制为0000,-1对应的二进制位1111,所以在逐字节赋值的时候不会产生赋值错误。

(2)  可以对char类型数组进行不同值的赋值,因为char类型正好只占用1字节,赋的值只要为char类型则不会出现(1)中的错误

(3)  ZeroMemory和memset在清零时回将结构体中所有字节置为0,如果结构体中含有虚函数或结构体成员中有虚函数,则会将虚函数指针置为0,如果后续程序通过指针调用虚函数,则这个空指针会造成崩溃,另外如果一个类的结构中包含STL模板(Vector、List、Map等),那么使用ZeroMemory对这个类的对象中进行清零操作也会引起一系列的崩溃问题(指针指向内存错误、迭代器越界访问等),所以建议:类只使用构造函数进行初始化,不要调用ZeroMemory进行清零操作
 

#include <iostream>
#include <string>
using namespace std;
 
struct s1
{
	int i;
	virtual void  fun(int a)
	{
		i = a;
	}
};
 
int main()
{
	s1 s;
	s.i = 10;
	s.fun(100);
	cout << s.i << endl;  //100
	memset(&s, 0, sizeof(s));
	s.fun(88);
	cout << s.i << endl;  //88
	(&s)->fun(99);  //此处引发了异常 __vfptr = 0x00000000,崩溃
	cout << s.i << endl; //并不能打印出数值
}

如上程序,在置0后,只有使用指针来调用该虚函数时会产生崩溃,通过对象调用则不会产生崩溃,并且如果函数只是普通函数而非虚函数,则置0后不会发生错误,因为普通函数没有虚函数指针,虚函数指针才会占用空间,所以在置0时被置为空指针。

ZeroMemory和memset的区别:
(1)  ZeroMemory是微软的SDK提供的,memset属于C Run-time Library提供的,因此ZeroMemory只能用于Windows系统,而memset还可用于其他系统
(2)  ZeroMemory是一个宏,只用于把一段内存的内容置零,内部其实是用memset实现的,而memset除了对内存进行清零操作,还可以将内存置成别的字符
(3)  如果程序是Win32程序而且不想连接C运行时库,那就用ZeroMemory,如果需要跨平台,那就用memset

ZeroMemory和“={0}”的区别:
(1)  ZeroMemory会将结构中所有字节置0,而“={0}”只会讲成员置0,其中填充字节不变
(2)  一个struct有构造函数或虚函数时,ZeroMemory可以编译通过,而“={0}”会产生编译错误,其中,“={0}”的编译错误起到了一定的保护作用,因为对一个有虚函数的对象使用ZeroMemory时,会将其虚函数的指针置0,这是非常危险的(调用虚函数时,空指针很可能引起程序崩溃)

部分借鉴自:https://www.cnblogs.com/lidabo/archive/2013/01/07/2848701.html
————————————————
版权声明:本文为CSDN博主「寂寂寂寂寂蝶丶」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/SwordArcher/article/details/83417950

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值