1

I would like to allocate nested data structures which are defined below with only one malloc call. Is it possible in C? If so, how can I do that?

struct s1 {
    int a;
    int b;
    char ns1[16];
};

struct s2 {
    struct s1 *ps1;
    int i;
    int j;
    char ns2[16];
};
albin
  • 773
  • 1
  • 8
  • 27

3 Answers3

1

This is not a nested structure because ps1 is a pointer, not a structure.

malloc() works just fine with pointers. You can allocate s2 with no problem. But you will have to point the ps1 member to something valid.

A nested structure would look more like this:

struct s2 {
    struct s1 x_s1;
    int i;
    int j;
    char ns2[16];
};

And malloc() should be okay with that one as well.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
1

A portable way to allocate space for multiple objects at once is to wrap them into a container structure:

struct PairHolder
{
    struct s2 first;
    struct s1 second;
};


// Postcondition: You own the result and must call free() on it (and on nothing
// else).

struct s2 * create_s2_and_s1()
{
    struct PairHolder *ph = malloc(sizeof(PairHolder));

    ph->first.ps1 = &ph->second;
    return &ph->first;
}
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    Note that with this technique, you can (and must) `free()` the `PairHolder` with the pointer returned from `create_s2_and_s1`. – OregonTrail Sep 03 '14 at 00:19
  • 2
    @OregonTrail `&ph->first` must indicate the same address as `ph` (structs cannot have initial padding); the language lawyers can debate whether freeing that pointer is correct – M.M Sep 03 '14 at 00:22
  • @OregonTrail: C structs have no initial padding. – Kerrek SB Sep 03 '14 at 00:23
  • @OregonTrail: If you like you should use `void destroy_s1_and_s2(void * p) { free((PairHolder*)p); }` – Kerrek SB Sep 03 '14 at 00:24
  • What part of "you can (and must)" in my comment did you not see? Yes, all of these comments are correct. – OregonTrail Sep 03 '14 at 00:29
0

After one day study, and based on previous answers. I came up with the solution below.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct s1 {
    int a;
    int b;
    char ns1[16];
};

struct s2 {
    struct s1 *ps1;
    int i;
    int j;
    char ns2[16];
};

int main(int argc, char *argv[])
{
    struct s2 *ps2;
    ps2 = malloc(sizeof(struct s1) + sizeof(struct  s2));
    ps2->ps1 = (struct s1 *)(ps2 + 1);

    ps2->ps1->a = 1;
    ps2->ps1->b = 2;
    strcpy(ps2->ps1->ns1, "s1");

    ps2->i = 3;
    ps2->j = 4;
    strcpy(ps2->ns2, "s2");        
    free(ps2);

    return 0;
}
albin
  • 773
  • 1
  • 8
  • 27