0

Assume I have this structure:

typedef struct foo
{
bool bar[4];
}foo;

and then I want to create an array of that structure:

foo foo_arr[] = {
{{true, true, false, true}}, 
{{false, true, false, true}}, 
{NULL}
};

Is the Initialization of the struct at foo_arr[2] valid? And if not, what is the correct way to point such array to NULL?

  • Requirement: The structure needs to be allocated on the stack.
avivgood2
  • 227
  • 3
  • 19
  • What is the size of the array? if you want a flexibe array member there must be at least one member before `arr` and you can not use more than one element in such case – David Ranieri Jun 20 '20 at 05:42
  • 2
    why do you even need `NULL` in the first place? how about sticking to 2 elements only? – Infinity Jun 20 '20 at 05:42
  • @Infinity this is just a demo. in my real code the struct has much more fields than just the array, but just the array should be NULL. – avivgood2 Jun 20 '20 at 05:45
  • @DavidRanieri what do you mean? should I post the full struct for context? – avivgood2 Jun 20 '20 at 05:46
  • 1
    Your edit doesn't change the behaviour, you need to define the size of the array, do you mean `bool bar[4];`? – David Ranieri Jun 20 '20 at 05:47
  • @DavidRanieri yes I forgot to add it, thanks! – avivgood2 Jun 20 '20 at 05:48
  • 4
    Arrays don't "point to" anything, and the use of `NULL` here has nothing to do with pointers (and you should probably use something else, as a style matter). You may benefit from reading through http://c-faq.com/aryptr/. – Karl Knechtel Jun 20 '20 at 06:04
  • Read the C11 standard [n1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf). See also [this draft](http://starynkevitch.net/Basile/bismon-chariot-doc.pdf) – Basile Starynkevitch Jun 20 '20 at 06:40
  • @Basile but this is ansi C – avivgood2 Jun 20 '20 at 07:00
  • Ansi C is an obsolete standard. It is difficult to find a compiler compatible with ANSI C. C11 is upward compatible. Read [n1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) and see [Modern C](https://modernc.gforge.inria.fr/). Consider using [GCC](http://gcc.gnu.org/) and [GDB](https://sourceware.org/gdb/). Provide some [mre] in your next question, yours is not clear. – Basile Starynkevitch Jun 20 '20 at 07:01

2 Answers2

3

In the same way you can not use:

int arr[] = {1, 2, NULL};

you can not set an element expecting a foo type to NULL, to do that you need to use an array of pointers to foo:

#include <stdio.h>
#include <stdbool.h>

typedef struct foo
{
    bool bar[4];
} foo;

int main(void)
{
    foo foo_arr[] = {{{true, true, false, true}}, {{false, true, false, true}}};
    foo *foo_ap[] = {&foo_arr[0], &foo_arr[1], NULL};

    for (int i = 0; foo_ap[i] != NULL; i++)
    {
        foo *foo_ptr = foo_ap[i];

        printf("%d %d %d %d\n",
                foo_ptr->bar[0],
                foo_ptr->bar[1],
                foo_ptr->bar[2],
                foo_ptr->bar[3]);
    }
    return 0;
}

Output:

1 1 0 1
0 1 0 1
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
2

"Is it OK to make a global stack allocated array point to NULL?"

"Is the init(ialization) of the struct at foo_arr[2] valid?"

No, it is not OK and not valid. At least not in the way you did (C syntax violation with {NULL} - it needs to be {{NULL}} to get compiled).

typedef struct foo
{
   bool bar[4];
} foo;

foo foo_arr[] = {
    {{true, true, false, true}}, 
    {{false, true, false, true}}, 
    {{NULL}}
};

Indeed, under some requirements this would initialize all elements of bar to 0, but lets start at the beginning.

Why would you want to use NULL? NULL is used to compare and set pointers, not data objects. bar is not an array of pointers.

I indeed had a similar question myself, a few months ago:

It is implementation-defined whether it is valid to use NULL to initialize data objects to 0, since the NULL macro either expands to 0 or (void*) 0. If it is the latter, the implementation needs to specify what happens if you assign a pointer to void to an integer type.

"Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type."

Source: C18, 6.3.2.3/6

So if either,

  1. NULL expands to 0 on your specific implementation, or
  2. The implementation specifies conversions from pointers to integers (the conversion from (void*) 0 to an data object),

this would indeed initialize all elements of bar in the third structure to 0, because of following:

In the first place, {{NULL}} set the first bool object in the array bar in the third structure of the array foo_arr to 0.

Implicitly it will also initialize all following three bool object to 0, because:

"If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than thereare elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration."

Source: C18, 6.7.9/20

This means if you intialize the first bool object it will automatically initialize all others.


"If not, what is the correct way to point such array to NULL?"

As said above, not to NULL, to 0 or false. The array (elements) do not point to anywhere. They are not pointers! As indicated above you can just use {{0}} or {{false}}:

typedef struct foo
{
   bool bar[4];
} foo;

foo foo_arr[] = {
    {{true, true, false, true}}, 
    {{false, true, false, true}}, 
    {{0}};
};