title: Struct with union static and dynamic char array
body: <p>I'm creating a dynamically allocated linked list where each item has a data element. Most of these elements are fixed size char arrays but some can be of varying length, E.g. only 1 or 2 chars - or 1000+.</p>
  
  <p>If I use a union inside the data element with static and dynamic char array – is it always going to occupy:</p>
  
  <ul>
  <li>size of the static one or if malloc'd the size of the malloced one?</li>
  <li>size of the static one + if malloc'd the size of the malloced one?</li>
  <li>the size of the pointer to the malloced one or the size of the static one?</li>
  <li>... (and so on)</li>
  </ul>
  
  <p>A simplified example without the list. This is not how I'm filling it with data, - only as an example of the struct union.</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;string.h&gt;
  
  enum meta_type {LIST, STRING};
  
  struct meta {
      union {
          char clist[128];
          char *cstr;
      } val;
      enum meta_type type;
  };
  
  int init_meta(struct meta *meta, enum meta_type type, int size, char *data)
  {
      if (type == STRING) {
          if ((meta-&gt;val.cstr = malloc(size + 1)) == NULL) {
              puts("Out of memeory");
              return 1;
          }
          sprintf(meta-&gt;val.cstr, "%s", data);
      } else {
          memset(meta-&gt;val.clist, 0, 128);
          meta-&gt;val.clist[0] = data[0];
          meta-&gt;val.clist[1] = data[1];
          meta-&gt;val.clist[2] = data[2];
      }
  
      meta-&gt;type = type;
  
      return 0;
  }
  
  void free_meta(struct meta *meta)
  {
      if (meta-&gt;type == STRING)
          free(meta-&gt;val.cstr);
  }
  
  int main(int argc, char *argv[])
  {
      struct meta meta;
      char list[] = {'a', '3', 'f'};
  
      if (argc &gt; 1) {
          if(init_meta(&amp;meta, STRING, strlen(argv[1]), argv[1]))
              return 1;
      } else {
          init_meta(&amp;meta, LIST, 0, list);
      }
  
      fprintf(stdout,
          "meta[%d]: %s\n",
          meta.type,
          meta.type == LIST ? meta.val.clist : meta.val.cstr
      );
  
      free_meta(&amp;meta);
  
      return 0;
  }
  </code></pre>
  
  <hr>
  
  <p>@Floris: One of the whacky ways I tested:</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;string.h&gt;
  #include &lt;stddef.h&gt;
  
  enum meta_type {LIST, STRING};
  
  #define SIZE_CLIST  128
  
  struct meta {
      enum meta_type type;
      union {
          char clist[SIZE_CLIST];
          char *cstr;
      } val;
  };
  
  int init_meta(struct meta **meta, enum meta_type type, int size, char *data)
  {
      if (type == STRING) {
          if (offsetof(struct meta, val) == 0) {
              puts("Ups.");
              return 2;
          }
          *meta = malloc(sizeof(struct meta) -
                  SIZE_CLIST +
                  sizeof(char *)
              );
          (*meta)-&gt;val.cstr = malloc(size + 1);
          if ((*meta)-&gt;val.cstr == NULL) {
              puts("Out of memeory");
              return 1;
          }
          sprintf((*meta)-&gt;val.cstr, "%s", data);
          puts((*meta)-&gt;val.cstr);
      } else {
          *meta = calloc(1, sizeof(struct meta));
          (*meta)-&gt;val.clist[0] = data[0];
          (*meta)-&gt;val.clist[1] = data[1];
          (*meta)-&gt;val.clist[2] = data[2];
      }
  
      (*meta)-&gt;type = type;
  
      return 0;
  }
  
  void free_meta(struct meta *meta)
  {
      if (meta-&gt;type == STRING)
          free(meta-&gt;val.cstr);
      free(meta);
  }
  
  int main(int argc, char *argv[])
  {
      struct meta *meta = NULL;
      char list[] = {'a', '3', 'f'};
  
      if (argc &gt; 1) {
          if(init_meta(&amp;meta, STRING, strlen(argv[1]), argv[1]))
              return 1;
      } else {
          init_meta(&amp;meta, LIST, 0, list);
      }
  
      fprintf(stdout,
          "meta[%d] %d: %s\n",
          meta-&gt;type,
          sizeof(*meta),
          meta-&gt;type == LIST ? meta-&gt;val.clist : meta-&gt;val.cstr
      );
  
      free_meta(meta);
  
      return 0;
  }
  </code></pre>