将结构初始化/重置为零/空


92
struct x {
    char a[10];
    char b[20];
    int i;
    char *c;
    char *d[10];
};

我填写此结构,然后使用值。在下一次迭代中,我想将所有字段重置为0null我开始再使用它之前。

我怎样才能做到这一点?我可以使用,memset还是必须仔细检查所有成员,然后逐个进行?

Answers:


109

使用初始值定义该结构的const静态实例,然后在每次要重置它时将其分配给变量即可。

例如:

static const struct x EmptyStruct;

在这里,我依靠静态初始化来设置我的初始值,但是如果您想要不同的初始值,则可以使用结构初始化器。

然后,每次循环,您都可以编写:

myStructVariable = EmptyStruct;

1
@David Heffernan:memset如果我只想将所有内容重置为0
哈里

9
@hari我更喜欢这个方法。使用memset使我感到肮脏。我宁愿让编译器尽可能地担心内存布局。严格来说,这种用法memset是不可移植的,但是实际上,如果您在任何重要的地方编译代码,我都会感到惊讶。因此,如果您愿意,可以安全地使用memset。
David Heffernan

2
@hari,从概念上讲更好,因为您提供了默认的初始化值(有点像对象工厂模式。)
Diego Sevilla

1
@cnicutar我知道这一点。请注意,我的答案建议不要使用memset。还要注意我指出使用memset作为分配空值的方法的不可移植性的注释。我之前的评论仅指出了一个事实,即0位始终对应于浮点零。
David Heffernan

1
请@ kp11引用
David Heffernan

85

当您使用现代C(C99)时,执行此操作的方法是使用复合文字

a = (const struct x){ 0 };

这有点类似于David的解决方案,只是您不必担心声明一个空结构或是否声明它static。如果const像我一样使用,则编译器可以在适当的情况下自由地在只读存储中静态分配复合文字。


是否在堆栈上创建x的实例,然后将其复制到a?对于大型结构/小型堆栈,这可能是个问题。
艾蒂安

1
像所有优化一样,这完全取决于编译器,因此您必须检查编译器生成的内容。在现代编译器上,“通常”不是这样,它们可以很好地跟踪初始化,只执行必要的事情,而不是更多。(也不要以为这样的事情在您测量出真正的减速之前就是问题。通常不是。)
Jens Gustedt 2014年

3
“缺少初始化器”警告确实是虚假的。C标准明确规定了要发生的事情,并将C { 0 }作为默认的初始化程序。关闭该警告,这是虚假的错误警报。
Jens Gustedt

1
@JensGustedt真的需要这种类型转换吗?我不能这样写吗?struct xa =(const){0};
Patrick

1
@Patrick,尽管语法相似,但这不是强制转换,而是“复合文字”。您正在混合初始化和分配。
詹斯·古斯特

58

使用标准C规范进行结构初始化是比上面更好的方法:

struct StructType structVar = {0};

这里都是零(永远)。


13
我不认为您可以每次都绕一个循环来做到这一点
David Heffernan

2
这确实是可行的。但不幸的是,gcc和g ++对此有所抱怨。gcc生成警告,而g ++生成错误。我知道gcc和g ++在此方面有错(应该遵循标准C规范),但是尽管如此,为了获得良好的可移植性,必须考虑到这种限制。
Cyan 2015年

3
@Cyan可以{}在C ++中使用。gcc开发人员似乎不确定C ++是否应该支持,{0}而我本人也不熟悉标准的那部分。

@Matthew:是的,实际上,我最终使用了memset(),因为{0}or 太多了可移植性问题{}。不知道C和C ++标准是否在此问题上明确并同步,但是显然编译器不是。
青色

在这种情况下可以工作吗?struct StructType structVar = malloc (sizeof(StructType)); structVar ={0}
山姆·托马斯

34

在C语言中,将struct使用的内存清零是一种常见的习惯用法memset

struct x myStruct;
memset(&myStruct, 0, sizeof(myStruct));

从技术上讲,我不认为这是可移植的,因为它假定NULL一台机器上的指针由整数值0表示,但是它被广泛使用,因为在大多数机器上都是这种情况。

如果从C转到C ++,请注意不要在每个对象上都使用此技术。C ++仅对没有成员函数且没有继承的对象将此合法化。


2
C标准指出NULL始终为0。如果将计算机设计为使预定的无效地址实际上不是0,则该体系结构的编译器必须在编译期间进行调整。
凯文M

8
@KevinM是的,即使全零,符号“ 0”也始终对应于NULL指针;但是如果您使用memset将位设置为零,编译器将无能为力。
Adrian Ratnapala 2012年

“ C ++仅在没有成员函数且没有继承的对象上使此合法。” 关于该类型是否被视为“普通旧数据”。条件取决于C ++语言的版本。
Max Barraclough

19

如果您具有符合C99的编译器,则可以使用

mystruct = (struct x){0};

否则,您应该做David Heffernan写的事情,即声明:

struct x empty = {0};

并在循环中:

mystruct = empty;

6

您可以使用memsetstruct的大小:

struct x x_instance;
memset (&x_instance, 0, sizeof(x_instance));

1
我认为这里不需要演员。是吗?
templatetypedef

好吧,我已经很习惯C ++了……很好,它也可以在C ++中工作,所以我不认为它是负担。
圣地亚哥塞维利亚

是的,我还不够具体。指向cv合格T的任何指针都可以转换为cv合格void *。任何数据指针,函数指针都完全不同。荣誉@凯文
马库斯·博肯哈

memset是一种选择,但使用时,必须确保使该内存写入正是大小作为第三个参数一样的,这就是为什么它是更好地指实际物体的大小,而不是类型的大小你知道目前是。IOW memset (&x_instance, 0, sizeof(x_instance));是更好的选择。顺便说一句:(void*)在C ++中,cast也是多余的。

(对不起,我错过了这个问题,现在好了)
Wolf

5

我相信您可以将空集({})分配给变量。

struct x instance;

for(i = 0; i < n; i++) {
    instance = {};
    /* Do Calculations */
}


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.