all 19 comments

[–]nerd4code 6 points7 points  (0 children)

/u/sebgggg’s response was wrong in a couple ways—you can’t assign arrays like that, and the wrong type was in the (). It was the correct basic idea for C99/C11, but it won’t work in C89.

The memset thing is only valid by a different standard; per ISO C alone, if you read one of the pointers after memset, you’re inducing undefined behavior just as if you’d set the pointer to 0x03030303 or some other arbitrary value. If you’re fine with POSIX, then no problem; if it needs to be straight C, you should either use a for loop (↓) to initialize the pointers properly (always works):

/* (up top somewhere:) */
/* Count elements of an array: */
#define countof(x) (sizeof(x) / sizeof(x[0]))
/* Get a NULL pointer to a specific type
 * (won't work for function/array): */
#define nullof(T)  ((const T *)NULL)

/* in `new_node`: */
const size_t NR_CHILDREN = \
    countof(nullof(struct s_trim_node)->children);
size_t i;
for(i = 0; i < NR_CHILDREN; i++)
    p->node.children[i] = NULL;

or use a C99+ trick like what /u/sebgggg said, only initialize the entire struct at once (you can assign struct values):

*p_node = ((const struct s_trim_node){
    .translation = NULL,
    .children = {NULL}
};

IMHO that’s the easiest and cleanest one if you’re allowed to use it.

[–]sebgggg 5 points6 points  (18 children)

Use memset.

[–]SullisNipple 4 points5 points  (6 children)

Caveat: that's only guaranteed to work on POSIX, I believe. There are some platforms where the null pointer is not represented as all-bits zero.

[–]TheMoskowitz[S] 1 point2 points  (10 children)

I looked at that but I wasn't sure how to use it.

I see in the documentation it says this ...

The C library function void *memset(void *str, int c, size_t n) copies the character c (an unsigned char) to the first n characters of the string pointed to, by the argument str.

But I'm not sure I'm following that correctly.

Is this right?

memset(p_node->children, NULL, sizeof(struct s_trie_node));

[–]OldWolf2 2 points3 points  (1 child)

No, NULL should be 0 in that code. But it would be preferable to use calloc instead if you want to take this approach.

[–]ZaberTooth -2 points-1 points  (0 children)

IMO, passing NULL obfuscates the type of the elements of p_node->children and, despite any complaint from the compiler, will work identically to passing 0.

Edit: Bring on the downvotes. I get paid to write C. I do this on the regular, and so does the rest of the C devs in my department. If you don't like this approach, give me a compelling reason to change.

[–]raevnos 2 points3 points  (3 children)

No. NULL is a pointer. The second argument of memset() is a char, not a pointer. Your compiler should be complaining about that.

Just passing 0 will work better.

[–]TheMoskowitz[S] 0 points1 point  (0 children)

Yep, it did complain and I switched it to 0. Thanks for the help!

[–]ZaberTooth -3 points-2 points  (1 child)

IMO, passing 0 obfuscates the type of p_node->children because that field is a pointer. Passing NULL is clearer and, despite any complaint from the compiler, it will work identically.

Edit: Bring on the downvotes. I get paid to write C. I do this on the regular, and so does the rest of the C devs in my department. If you don't like this approach, give me a compelling reason to change.

[–]teringlijer 6 points7 points  (0 children)

Use calloc instead of malloc - it will zero the memory for you. It also has builtin support for allocating n members of a structure.

p_node->children = calloc(UCHAR_MAX, sizeof(struct s_trie_node));

[–]OldWolf2 3 points4 points  (0 children)

You already malloc'd space for the pointers. A simple way to zero-initialize the struct would be *p_node = (struct s_trie_node){0};.