请说明结构体初始化数据赋值的几种方式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请说明结构体初始化数据赋值的几种方式相关的知识,希望对你有一定的参考价值。

结构体能自由组装数据,是一种很常见的数据打包方法。当我们定义一个结构体后,没有初始化就使用,就会使用到垃圾数据,而且这种错误很难发现。对于定义的任何变量,我们最好都先初始化。

除了使用memset和ZeroMemory之外,有没有更简单的方法初始化呢?因为有时候每定义一个结构体,就使用一次memset,也会觉得很繁琐。

我这里总结三种方法,如果大家有什么好的方法,不妨加上去。

1、结构体的构造函数中初始化。

2、继承模板类初始化

3、定义时初始化
在C++中,结构体与类在使用上已没有本质上的区别了,所以可以使用构造函数来初始化。如下代码所示:
struct Stu

int nNum;
bool bSex;
char szName[20];
char szEmail[100];
//构造函数初始化
Stu()

nNum = 0;
bSex = false;
memset(szName,0,sizeof(szName));
memset(szEmail,0,sizeof(szEmail));

;
你可能已经发现了,如果结构体中有大量成员,一个个赋值,相当麻烦。那么你可以这样写:
struct Stu

int nNum;
bool bSex;
char szName[20];
char szEmail[100];
//构造函数初始化
Stu()

memset(this,0,sizeof(Stu));
//或者是下面的格式
//memset(&nNum,0,sizeof(Stu));

;

如果在结构体中分配了指针,并且指针指向一个堆内存,那么就在析构函数中释放。以上便是在构造函数中初始化。
2、继承模板类初始化
首先定义一个模板基类:
template <typename T>
class ZeroStruct

public:
ZeroStruct()

memset(this,0,sizeof(T));

;
之后定义的结构体都继承于此模板类。
struct Stu:ZeroStruct<Stu>

int nNum;
bool bSex;
char szName[20];
char szEmail[100];
;
这样也能实现初始化。
3、定义时初始化。
struct Stu

int nNum;
bool bSex;
char szName[20];
char szEmail[100];
;

//定义时初始化
Stu stu1 = 0;
在有的结构体中,第一个成员表示结构体的大小,那么就可以这样初始化:
struct Stu

int nSize; //结构体大小
int nNum;
bool bSex;
char szName[20];
char szEmail[100];
;
Stu stu1 = sizeof(Stu),0;
后面的0,可以省略掉,直接写成:Stu stu1 = sizeof(Stu);后面自动会用0填充。
总结分析:
以上三种,是据我所知的初始化结构体方法。
前面两种,实际上已经把结构体给类化了,和类的使用差不多。第三种,是纯粹的结构体的写法。
如果用途仅仅限定为结构体,我建议不要加上构造函数,也不要继承于那个模板类,因为这个时候结构体实际上已经是类了。在定义结构体时,将无法使用第三种方式去初始化,当然,此时也不需要初始化了。
看看微软定义的结构体,基本上都没有构造函数和析构函数。因为结构体的意义很明确,它仅仅是对数据的一个包装,如果加上了方法,其意义就变了。

自己的总结:
关于第三种初始化方法,类似于数组的初始化。
参考技术A C Primer里写很全。
包括最新的标号赋值。
使用大括号赋值;
逐个成员变量赋值;
整个结构体赋值,一般是memset;
C99的标号赋值。
参考技术B main函数里面,方法里面

小结:二叉树的几种实现方式

前言

比较常规的二叉树的实现方式是[结构体/对象+指针],看紫书的时候,里面给出了几种树的实现方式,基本上是比较适合在比赛中使用的。

1.结构体+指针

struct Node {
	bool p; 
	int v;
	Node * left;
	Node * right;
	Node(): p(0), left(NULL), right(NULL) {}
};
Node* new_node() 
{
	return new Node();
}
void remove_tree(Node * u) 
{
	if(u == NULL) return;
	remove_tree(u->left);
	remove_tree(u->right);
	delete u;
}

最常规的实现方式,结构体中p用来标识是否存在/被赋值过。这一方式为动态分配内存,删除树或某一子树时采用递归delete释放内存。

 

2.数组+ID

const int max_n = 1000, rootID = 1;
int val[max_n], left[max_n], right[max_n], nodeID;
bool present[max_n];

void new_tree()
{
	left[rootID] = right[rootID] = 0; present[rootID] = 0;
	nodeID = rootID;
}

int new_node()
{
	int u = ++nodeID;
	left[u] = right[u] = 0; present[u] = 0;
	return u;
}

由于动态分配内存是非常耗时的操作,因此我们想用静态方式来替代。每一个节点拥有独自的nodeID,根节点rootID为常量1,left[i],right[i]数组是第i节点的子节点ID,相当于指针。

分配新节点只需要初始化++nodeID节点的各项值就好,省去了动态分配内存的时间。而删除节点,若删除节点i的左孩子,只需要left[i] = 0就行,免去了释放内存的麻烦。分配新树只需要将nodeID重置就行。

然而这种方法存在内存碎片无法利用的问题,由于nodeID是一直递增的,若对树的删除操作较多,会导致数组中很多部分不能再利用,或者说树节点数组规模难以确定。

 

3.结构体数组+ID

struct Node {
	bool p; 
	int v;
	Node * left;
	Node * right;
	Node(): p(0), left(NULL), right(NULL) {}
};
const int max_n = 1000, rootID = 1;
int nodeID;
Node node[max_n];

void new_tree(Node *u)
{
	Node* u = &node[rootID];
	u->left = u->right = NULL; u->p = 0;
	nodeID = rootID;
}

Node* new_node()
{
	Node* u = &node[++nodeID];
	u->left = u->right = NULL; u->p = 0;
	return u;
}

指针访问会比数组下标快一些,但使用结构体更主要的原因还是因为能更好地将各项属性组织起来,优于数组的表达效果。

思路上与[数组+ID]相差不同,同样也有内存碎片无法利用的问题。

 

4.结构体数组+内存池

struct Node {
	bool p;
	int v;
	Node * left;
	Node * right;
	Node(): p(0), left(NULL), right(NULL) {}
};

const int max_n = 1000;
queue<Node*> node_pool;
Node node[max_n];

void init()
{
	for(int i = 0; i < max_n; i++)
		node_pool.push(&node[i]);
}

Node* new_node()
{
	Node* u = node_pool.front(); node_pool.pop();
	u->left = u->right == NULL; u->p = 0;
	return u;
}

void delete_node(Node* u)
{
	node_pool.push(u);
}

为了解决内存碎片无法利用的问题,可以采用内存池管理。建立一个Node*的队列,初始化时将Node数组中所有项的指针入队。分配新节点时,从队列中出队取指针;删除节点时,将节点重新入队即可。

 

总结

以上几种实现方式,主要区别在于:1.内存分配是动态还是静态;2.是否有内存碎片无法利用。根据题目特点,是否需要频繁插入节点,是否会对树进行删除等等,选择合适的实现方式。

以上是关于请说明结构体初始化数据赋值的几种方式的主要内容,如果未能解决你的问题,请参考以下文章

C语言中结构体初始化的方法

C语言怎么给结构体里的结构体赋值?

c语言怎么结构数据初始化?

宏定义中对结构体变量进行初始化,结构体成员变量前为啥加点号??

C语言数据类型——结构体

C语言数据类型——结构体