views:

49

answers:

2

The objective is to build a "infinite" tree using dynamic arrays.

items[3]
- MENUITEM
  - items[2]
    - MENUITEM
      -items[0]
    - MENUITEM
      - items[0]
- MENUITEM
  - items[0]
- MENUITEM
  - items[2]
    - MENUITEM
      - items[0]
    - MENUITEM
      - items[0]

I define the structure:

typedef struct MENUITEM {
    char id, count;
    char *description;
};

And I can allocated items dynamically with:

char count;
MENUITEM items[], *items_ptr;

count++;
realloc( items_ptr, count * sizeof(struct MENUITEM) );

The problem is that inside the structure I cannot assign again the structure itself like:

typedef struct MENUITEM {
    char id, count;
    char *description;

    MENUITEM items[], *items_ptr;
};

The compiler outputs: error: field ‘items’ has incomplete type; what am I doing wrong here ? Thanks for any help provided.

+1  A: 

You need to use struct MENUITEM *items_ptr;. Note the use of the word struct.

Why do you have MENUITEM items[]? It's not used for anything.

Do this instead:

typedef struct MENUITEM {
    char id, count;
    char *description;

    struct MENUITEM *items;
} MENUITEM;

void foo() {
    MENUITEM *root = (MENUITEM*)malloc(sizeof(MENUITEM));

    root->id = 87;
    root->count = 5;

    root->items = (MENUITEM*)malloc(sizeof(MENUITEM)*root->count);
}
Borealid
items[] is used further ahead on the code like (after the realloc):items[ this->count -1 ].id = 1337;items[ this->count -1 ].description = "Some stuff";
Joao
@Joao: Example granted. Fixed your errors.
Borealid
Thanks ! I was accessing the childs like: "items[ parent_id ].items[ count -1 ].id = id;", how should them be accessed now ?
Joao
@Joao: Use `items[x]->items[y]->items[z]->id`.
Borealid
This means that every item is a pointer to another MENUITEM struct ?
Joao
@Joao: Oops, sorry, it's still `items[x].items[y].items[z].id`. I didn't think that through very well before typing.
Borealid
A: 

Change the MenuItem structure to hold a pointer to MENUITEM

typedef struct MENUITEM {
    char id, count;
    char *description;

    MENUITEM *items_ptr;
};

Not alone that the allocation is not good either - it would be much slower doing this

count++;
realloc( items_ptr, count * sizeof(struct MENUITEM) );

You would be better off allocating a block of memory say to hold 50 entries, when the limit has reached, realloc it with twice the block size and please ensure that you do not clobber the result like this:

Correct:

MENUITEM *temp_items_ptr;
temp_items_ptr = realloc( items_ptr, count * sizeof(struct MENUITEM) );
if (temp_items_ptr != NULL){
   items_ptr = temp_items_ptr;
}else{
   /* Handle the out of memory situtation */
}

Wrong:

items_ptr = realloc( items_ptr, count * sizeof(struct MENUITEM) );

The wrong approach is a recipe for disaster and say hello to leaked memory!

tommieb75
I consider your advice a wise one but on the context where this code will be run, running out of memory is very easy (Arduino development board).
Joao