views:

96

answers:

2

I have a struct which is a node, and another which is a list of these nodes. In the list struct, its an array of nodes, but instead of an array, it's a pointer to pointer with a size integer:

typedef struct node {
    struct node *next;
    MyDef *entry;
} Node;


typedef struct list {
    Node **table;
    int size;
} List;

List *initialize(void)
{
    List *l;
    Node **n;

    if ((l = (List *)malloc(sizeof(List))) == NULL)
        return NULL;
    l->size = 11;

    /* I think this is correctly allocating the memory for this 'array' of nodes */
    if ((n = (Node **)malloc(l->size * sizeof(Node))) == NULL)
        return NULL;

    /* Now, how do I set MyDef *entry and Node *next to NULL for each of the 'array'? */

    l->table = n;

    return l;
}

How do I set MyDef *entry and Node *next to NULL for each of the 'array'?

A: 

First of all, it seems to me that you have an error in your code allocating the array: It should say sizeof(Node*) rather than sizeof(Node) as you want to allocate an array of pointers to Node not an array of Node objects.

Then you can iterate through the array list:

for ( unsigned i = 0; i < l->size; ++i )
{
    Node* node = l->table[ i ];
    node->entry = NULL;
    node->next = NULL;
}

Another hint: You really should check your initialization function against possibilities of memory leaks.

Flinsch
Thanks, tried this and get an error:l->table CXX0030: Error: expression cannot be evaluated
Igor K
Any idea why this isn't working? The VS 2010 debugger breaks on Node* node = l->table[i];
Igor K
I forgot: The individual objects have to be created as well. But it seems not to be the problem in your case as the error already occurs in the line accessing the table. But, just to have it correct, there is need for something like `l->table[i] = malloc(sizeof(Node))`.
Flinsch
Thanks @Flinsch, I put that line in immediately before the Node* node = ... line and it still broke on the Node* node = ... line!
Igor K
Did you try the debugger having a look at the values of `l` and `l->table` at that line immediately before the program crashes?
Flinsch
+1  A: 

(Node **) is pointer to [array of] pointer to Node, so array you allocate will not have any struct members.

You should use (Node *) and then you'll have pointed array of Node structs, or allocate each Node separately, then place pointers to them into your array.

There's exist function calloc() in standard C library for your case: it inits allocated area with 0's (which corresponds to (char/short/int/long)0, 0.0 and NULL).

Also there's a memory leak.

/* I think this is correctly allocating the memory for this 'array' of nodes */
if (... == NULL)
    return NULL;

When array allocation fails you do not free List, but lose pointer to it. Rewrite it as:

/* I think this is correctly allocating the memory for this 'array' of nodes */
if ((n = (Node **)malloc(l->size * sizeof(Node))) == NULL) {
    free(l);
    return NULL;
}

So from my point of wiev correct code would be:

typedef struct node {
    struct node *next;
    MyDef *entry;
} Node;


typedef struct list {
    Node *table; /* (!) single asterisk */
    int size;
} List;

List *initialize(void)
{
    List *l;
    Node **n;

    if ((l = (MList *)malloc(sizeof(List))) == NULL)
        return NULL;
    l->size = 11;

    /* I think this is correctly allocating the memory for this 'array' of nodes */
    if ((n = (Node *)calloc(l->size, sizeof(Node))) == NULL)
    {
        free(l);
        return NULL;
    }

    /* Now, how do I set MyDef *entry and Node *next to NULL for each of the 'array'? */

    l->table = n;

    return l;
}

Futhermore C99 allows you to make variable size structs, so you able to init struct like

typedef struct list {
    int size;
    Node table[0]
} List;

And allocate as many Node's in table as you want using malloc(sizeof(List) + sizeof(Node)*n);

Vovanium
Thank you ever so much for taking the time to do this. I'm trying this out as I type this.
Igor K
Just tried this, although this bit works great, I really do think I need the Node**. Reason is, in another bit of the program, I do "n->next = (*l)->table[int val];", where int val is < l->size. This doesnt work without the ** as its not an array?
Igor K
Vovanium
Thanks @Vovanium. Just one last error: should Node **n be Node *n? Otherwise VS 2010 doesnt like "n = (Node *)calloc...". Also VS 2010 is breaking on "l->table = n;"?
Igor K
Oh, you're right, 'Node *n' is correct, i missed this when edited the source.
Vovanium
@Vovanium, putting Node *n just makes the one error - its breaking on "l->table = n;", any ideas?
Igor K
Hmm, my GCC compiles this just fine. (The only replacement MList > List, as this is just typo). I cannot advise something without knowing what your compiler complains. Check your asterisks here ' Node *table;'
Vovanium
I've installed GCC now and will give it a go, actually another program which compiled on GCC didnt with MS VS2010. Thanks again Vovanium - will post back here shortly.
Igor K
Question: I cant seem to do "(l)->table+val = n", ie set a position of the 2D array of Node to a Node n. Invalid lvalue, which I don't really see why?
Igor K
I do not completely understand what you're want to do, but anyway result of arithmetic operation cannot be assigned. Also arrays in C have no positions. They're always pointed by 0-th elememt.
Vovanium
Really, I want to set n at position val in the table. ie l->table[val] = n. But I can't do table[val], this has to be table+val, moving the pointer directly, right?
Igor K
ps, thanks again - wish I could somehow up your rep in some way
Igor K