初始化struct数组成员的最有效方法?

时间:2020-07-07 19:22:02

标签: c

我已经声明了结构

struct wnode {
  char *word;
  int lines[MAXLINES];
  struct wnode *left;
  struct wnode *right;
};

和指针

struct wnode *p;

将指针传递给函数。 在该函数中,我首先使用malloc为指针分配内存。然后我想将结构成员 lines 初始化为零将结构成员 lines 归零。

数组初始化方法将不起作用,因为它被解释为赋值:

p->lines[MAXLINES] = {0};

编译器抛出错误:

错误:“ {”令牌之前的预期表达式

最后,我只是使用for循环将 lines 数组归零:

for (i = 0; i < MAXLINES; i++)
  p->lines[i] = 0;

有更好的方法吗?

9 个答案:

答案 0 :(得分:6)

不能将数组直接分配给。您需要使用循环将所有字段设置为0,也可以使用memset

memset(p->lines, 0, sizeof(p->lines));

请注意,对于非字符类型,只能将所有成员设置为0。对于其他任何值,都需要循环。

答案 1 :(得分:5)

如果您想使用=运算符,可以通过以下方式进行操作:

struct wnode wn, *p;
/* ........ */
wn = (struct wnode){.word = wn.word, .lines = {0,}, .left = wn.left, .right = wn.right};
*p = (struct wnode){.word = p ->word, .lines = {0,}, .left = p -> left, .right = p -> right};

答案 2 :(得分:4)

= {0}仅适用于初始化。您不能将其与分配一起使用,这就是为什么您会收到错误消息。

您可以按照您所说的使用for循环,也可以使用memset将数组归零:

memset(p -> lines, 0, sizeof(p -> lines))

答案 3 :(得分:2)

只能以这种方式初始化数组变量:

int someInt[MAXLINES] = {0};

在声明中。

但是由于此特定变量int lines[MAXLINES];是在struct的范围内声明的,因此不允许初始化成员,因此该方法失去了机会,要求在事实发生后对其进行初始化,并使用其他方法。

在这种情况下,声明后初始化的最常见(也是首选)方法是使用:

//preferred
memset(p->lines, 0, sizeof(p->lines));

一种比较费力的方法,并且经常看到,它在循环中将每个元素设置为所需的值:

for(int i=0;i<MAXLINES;i++)
{
    p->lines[i] = 0;
}

正如评论中所指出的,无论如何,一个好的优化编译器将把这种方法减少到相当于memset()语句。

答案 4 :(得分:1)

void *memset(void *s, int c, size_t n)

memset()函数填充内存区域的前n个字节 指向s的常量字节c。

memset()函数返回一个指向存储区s的指针。

尽管(sizeof(int)*MAXLINES)sizeof(p->lines)的字节结果相同,并且都是正确的 BUT ,但第二个选项(sizeof(p->lines))更好用,因为如果我们决定更改数组类型或数组大小,则无需更改szieof运算符内的表达式。我们只在一个地方改变。所以我们让编译器为我们完成工作!

#include <string.h>  /*for the memset*/
memset(p->lines, 0x0, sizeof(p->lines));

答案 5 :(得分:1)

此指针声明

struct wnode *p;

如果指针具有静态存储持续时间,则将指针p零初始化,或者如果指针具有自动存储持续时间,则使指针未初始化,因此将运算符->应用于指针会调用未定义的行为,因为指针确实没有指向有效的对象。

如果假设指针指向有效对象,例如

struct wnode w;

struct wnode *p = &w;

然后在函数中,您可以使用标准C函数memset初始化对象w的数据成员行。例如

memset( p->lines, 0, MAXLINES * sizeof( int ) );

您可能不会只在函数中编写

p->lines = {0};

因为已创建了指向对象,并且在数组的声明中允许进行此类初始化。而且数组没有赋值运算符。

答案 6 :(得分:1)

这种初始化只能在声明时完成。注意,在p->lines[MAXLINES] = {0};中,表达式p->lines[MAXLINES]表示 p->行末尾的整数。 您可以写p->lines[MAXLINES] = 0;。不正确,但可以编译。

您不再具有 array 的概念。您可以使用p->lines(它是一个指向int的指针)或p->lines[index](它是一个int)。

是的,您已经分配了空间,仅此而已。 memset可以解决问题。

顺便说一句,希望您的函数(或调用方)分配wnode元素...

答案 7 :(得分:1)

{0}仅在初始化中起作用,而不在分配中起作用。 由于无法初始化指针目标,只能对其进行分配,因此可以通过分配刚初始化的复合文字来解决该问题。

编译器通常会优化复合文字并将其直接分配给目标。

{0}初始化大型数组通常会编译为对memset或等效程序集的调用,因此另一种选择是手动在memset上直接调用p->lines。 / p>

示例:

#define MAXLINES 100
struct wnode {
  char *word;
  int lines[MAXLINES];
  struct wnode *left;
  struct wnode *right;
};

//(hopefully) elided compound literal
void wnode__init(struct wnode *X)
{
    *X = (struct wnode){"foo",{0},X,X};
}

//explicit memset
#include <string.h>
void wnode__init2(struct wnode *X)
{
    X->word = "foo";
    memset(X->lines,0,sizeof(X->lines));
    X->left = X;
    X->right = X;
}

https://gcc.godbolt.org/z/TMgGqV

答案 8 :(得分:0)

@ ikegami对原始问题的评论需要作为答案。

使用calloc()而不是malloc()

struct wnode *p;

// presumably you have N as the number of elements and
p = malloc(N * sizeof *p);
// replace with
//p = calloc(N, sizeof *p);
相关问题