ataraxis
ataraxis

Reputation: 1562

C - declare and init array inside struct

language: C

i am trying to declare and initialize an array inside a struct and pass it to a pointer, which is itself declared in the struct xD

yes, i know my attempt is... let's say "not correct" :D but it would be very useful if something similar would exist.

any ideas?

struct structname {
    int* section_A;
    int* section_B;
};

static const struct structname structvariable_a = {

    .section_A = (int[]) {
            [0x01] = 1,
            [0x02] = 2,
            [0x03] = 3
        },

    .section_B = (int[]) {
            [0x33] = 4,
            [0x34] = 5
        },

};

static const struct structname structvariable_b = {

    .section_A = (int[]) {
            [0x01] = 10,
            [0x02] = 20,
            [0x03] = 30
        },

    .section_B = (int[]) {
            [0x33] = 7,
            [0x34] = 8
        },

};

later, i want to access the values ...

int main()
{

    struct structname* structvariablepointer;

    if(foo == 1){
        structvariablepointer = &structvariable_a;
    } else {
        structvariablepointer = &structvariable_b;
    }

    printf("%i", ARRAY_SIZE(structvariablepointer->section_A));     // ARRAY_SIZE(arr) equals sizeof(arr) / sizeof(arr[0]));

    int b = 2;

    printf("%i", structvariablepointer->section_A[b]);
}

the only error is

./include/linux/build_bug.h:29:45: Fehler: Negative Breite in Bitfeld »<anonym>«
 #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:(-!!(e)); }))
                                             ^
./include/linux/compiler-gcc.h:64:28: Anmerkung: bei Substitution des Makros »BUILD_BUG_ON_ZERO«
 #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
                            ^~~~~~~~~~~~~~~~~
./include/linux/kernel.h:60:59: Anmerkung: bei Substitution des Makros »__must_be_array«
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
                                                           ^~~~~~~~~~~~~~~

Upvotes: 1

Views: 3600

Answers (3)

M.M
M.M

Reputation: 141544

Once you take a pointer to the first element of an array, you can no longer find the size of the array through that pointer. So you will also need to make variables to hold the array size. (Or use a sentinel value for the end of the array).

One way to solve your problem would be through ugly macros:

#include <stddef.h>
#define ARRAY_SIZE(a) ( (sizeof(a)) / sizeof((a)[0]) )


struct structname {
    int* section_A;
    size_t A_len;
    int* section_B;
    size_t B_len;
};

#define A_INIT (int[]) { 0, 1, 2, 3 }
#define B_INIT (int[]) { [0x33] = 1, [0x34] = 2 }

static const struct structname structvariable_a =
{
    .section_A = A_INIT,
    .A_len = ARRAY_SIZE(A_INIT),
    .section_B = B_INIT,
    .B_len = ARRAY_SIZE(B_INIT)
};
#undef A_INIT
#undef B_INIT

It would also be possible to define static named int arrays and then use that array's name in the initializers for structvariable_a.

Consider using int const * and int const[] respectively, if you don't intend to change the contents of the arrays at runtime. Note that if this code is in a header, each translation unit will have their own copy of the arrays.


Update (as suggested by comment): using a sentinel value would look like:

struct structname {
    int* section_A;
    int* section_B;
};

static const struct structname structvariable_a = 
{
    .section_A = (int[]) { 0, 1, 2, 3, INT_MAX },
    .section_B = (int[]) { [0x33] = 1, [0x34] = 2, INT_MAX }
};

and the in main or whatever, you look for INT_MAX to know where the end of the array is, e.g.:

size_t a_len;
for (a_len = 0; structvariable_a.section_A[a_len] != INT_MAX; ++a_len) { }

Obviously this means the range of valid data for the array needs to exclude the sentinel value.

Upvotes: 1

John Bollinger
John Bollinger

Reputation: 180103

i am trying to declare and initialize an array inside a struct and pass it to a pointer, which is itself declared in the struct xD

That doesn't make any sense whatever, but your actual code is almost completely correct in C99 and later. In particular, this:

(int[]) {
            [0x01] = 1,
            [0x02] = 2,
            [0x03] = 3
        }

Is neither a declaration of nor (quite) an initialization of an array; rather, it is a compound literal of type array of int. Because arrays decay to pointers in the context given, as in most, such a compound literal can indeed be used to initialize a structure member of type int * (to point to the first element of the array). Having successfully initialized those two struct structname objects, you can certainly obtain their addresses and record those in variables.

HOWEVER, a pointer to an array element does not carry information about the number of elements in the array. If that's all you have, as is the case in your main() function, then you cannot determine the number of array elements from it. You need to be able to determine that from the content (this is why C strings must be null-terminated), or you must have that information from some other source, such as a function argument, a variable, or clairvoyance.

yes, i know my attempt is... let's say "not correct" :D but it would be very useful if something similar would exist.

If you declare the members of struct structname to be bona fide arrays then you can access and use their declared lengths. If you prefer, you can store the number of array elements in additional members of that struct. Both of those approaches are used in the wild, as are approaches based on the contents of the pointed to elements. But I don't foresee C ever gaining a facility for making your ARRAY_SIZE() macro work with pointers as it seems you would like.

Upvotes: 1

dbush
dbush

Reputation: 223699

The error you're getting is because ARRAY_SIZE expects an array, and structvariablepointer->section_A is not an array but a pointer.

Since your structs effectively have fixed size arrays, just declare them as arrays instead of pointers:

struct structname {
    int section_A[4];
    int section_B[0x35];
};

Then initialize like this:

static const struct structname structvariable_a = {

    .section_A = {
            [0x01] = 1,
            [0x02] = 2,
            [0x03] = 3
        },

    .section_B = {
            [0x33] = 4,
            [0x34] = 5
        },
};

Upvotes: 1

Related Questions