user3649886
user3649886

Reputation: 15

How to initialize array of structures after declaration in C

Is there a way to initialize the whole array of structures (maybe using compound literals) after it is being declared?

typedef struct
{
    int a;
    int b;
} tStruct;

/* Array of structures in declared in global scope, but not initialized */
tStruct myStruct[3];

void init()
{
  /* We want to initizlize the array with specific values*/
  
  /* using compound literals to initialize the whole array doesn't work */
  myStruct = (tStruct[])
  {
      {1, 2},
      {3, 4},
      {5, 6}
  }; 
}

Upvotes: 1

Views: 1173

Answers (3)

Petr Skocik
Petr Skocik

Reputation: 60163

Arrays aren't R values, so you can't copy them via assignemnt. But you can use memcpy

#include <string.h>
void init(void)
{
    memcpy(&myStruct,(tStruct[]) { {1, 2}, {3, 4}, {5, 6} }, sizeof(myStruct)); 
}

The code generated by an optimizing compiler shouldn't be much worse than what you'd get with

void init2(void)
{
    myStruct[0] = (tStruct){1,2};
    myStruct[1] = (tStruct){3,4};
    myStruct[2] = (tStruct){5,6};
}

or

void init3(void)
{
    myStruct[0].a = 1, myStruct[0].b = 2;
    myStruct[1].a = 3, myStruct[1].b = 4;
    myStruct[2].a = 5, myStruct[1].b = 6;
}

Gcc and clang are well capable of eliding an unnecessary compound variable like that in favor of assigning individual components directly.

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

The biggest downside of the memcpy approach is that it's a bit brittle and type-unsafe (and can result in out-of-bounds reads/writes if the unenforced type compatibility is violated).

If your C dialect has __typeof, then with some macro trickery you should be able to almost get around this C language limitation:

#include <string.h>
#define assignAnything(DestPtr,SrcPtr) ((void)((__typeof(SrcPtr)){0} = (__typeof(DestPtr)){0}) /*typecheck*/, memcpy(DestPtr, SrcPtr, sizeof(*(DestPtr))))

/* A Ptr-less version:
#define assignAnything2(Dest,Src) ((void)((__typeof(&(Src))){0} = (__typeof(&(Dest))){0}), memcpy(&(Dest), &(__typeof(Src)){Src}, sizeof(Dest)))
doesn't always work, unfortunately */

int main()
{
    int d[3][2][1]={0};
    int const s[3][2][1] = {0};
    assignAnything(&d,&s); //works
    #if NOPE
    assignAnything(&s,&d); //will (correctly) compile-time fail because s has more qualifs (const) than d
    #endif
}

Upvotes: 2

Micha&#235;l Roy
Micha&#235;l Roy

Reputation: 6487

For arrays, compound literals only work on the statement declaration. You have to use individual assignments, loops, memcpy() or memset() to initialize arrrays and structs after that.

Example, to obtain same result:

typedef struct
{
    int a;
    int b;
} tStruct;

/* Array of structures in declared in global scope, but not initialized */
tStruct myStruct[3];

void init()
{
  /* Initizlize the array with specific values*/
  int i;
  const tStruct second_element = { 3, 4 };

  // member by member...
  myStruct[0].a = 1;
  myStruct[0].b = 2;

  // using struct copy.
  myStruct[1] = second_element;

  // or a loop...
  for (i = 2; i < 3; ++i)  // I know, there are only 3 elmments, but you get 
                           // the idea.. 
  {
      myStruct[i].a = (2 * i) + 1;
      myStruct[i].b = myStruct[i].a + 1;
  }
}

Upvotes: 0

koder
koder

Reputation: 2103

No, that does not work as you cannot assign one array to another.

But you can use memcpy to get around it

void init()
{
   tStruct data[3] = {
      {1, 2},
      {3, 4},
      {5, 6}
   };
   memcpy(mystruct, data, sizeof(mystruct));
}

But, be careful as the size of the data must match exactly.

Upvotes: 1

Related Questions