2

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))
                                                           ^~~~~~~~~~~~~~~
4
  • Possible duplicate of How I can declare arrays in struct? Commented Dec 6, 2017 at 20:19
  • @user-44651 - the link you refer to is tagged c#, which is a completely different language with different rules. IMO, This is not a duplicate of that. Commented Dec 6, 2017 at 20:22
  • Until you create space for: int* section_A;, the elements you refer to in static const struct structname structvariable_b = {... do not exist. And if you know there will be three elements at compile time, why don't you just create it as: int section_A[3];? In general, it is best to use stack memory unless you cannot know the size of something until runtime. Commented Dec 6, 2017 at 20:30
  • I am going to delete this question since nobody upvoted it - and therefore I am not allowed to ask something anymore... I someone is against the deletion, please tell me. Commented Feb 21, 2019 at 18:04

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

very useful :) i will upvote as soon as my reputation is high enough. thank you!
can you maybe add an example for the "sentinel thing"?
1

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
        },
};

1 Comment

thanks! but i would prefer to calculate the size at comilation time since i want to keep the code as easy to extend as possible :)
1

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.

3 Comments

i would like to upvote your answer as "(very) useful" - but my reputation is too low. i will do that as soon as i am allowed too ;) thanks!
can you think of any similar code that doesn't reserve 35 elements if only two are filled?
Sure, @flood, you could use a linked list, or a hash table, or any number of other data structures. There are tradeoffs involved with each. Some win on space usage only for much sparser data than you present. Few, if any, can be initialized as cleanly as the array version. I wouldn't sweat the space usage unless it's a bona fide problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.