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'?

Igor K
  • 95
  • 1
  • 2
  • 9
  • too many stars ... you use `**` for "2D arrays", not for a list of 'simple' elements – pmg Oct 26 '10 at 09:56
  • Taken from here: http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_hashtable.aspx – Igor K Oct 26 '10 at 10:01

2 Answers2

1

(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
  • 3,798
  • 17
  • 23
  • Thank you ever so much for taking the time to do this. I'm trying this out as I type this. – Igor K Oct 26 '10 at 16:21
  • 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 Oct 26 '10 at 16:37
  • n->next is a pointer to Node, (l)->table[val] is a Node, so you have to get pointer to it. Write &((l)->table[val]) or shorter (l)->table+val (table+val gives you pointer to val-th element of table). Node** will actually denote array of pointer to Node's, so in this case you should also allocate space for every node and store pointer to it in array elements. – Vovanium Oct 26 '10 at 19:04
  • 1
    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 Oct 26 '10 at 22:16
  • Oh, you're right, 'Node *n' is correct, i missed this when edited the source. – Vovanium Oct 26 '10 at 22:24
  • @Vovanium, putting Node *n just makes the one error - its breaking on "l->table = n;", any ideas? – Igor K Oct 26 '10 at 22:31
  • 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 Oct 26 '10 at 22:49
  • 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 Oct 26 '10 at 22:56
  • 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 Oct 26 '10 at 23:02
  • 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 Oct 26 '10 at 23:14
  • 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 Oct 26 '10 at 23:17
  • ps, thanks again - wish I could somehow up your rep in some way – Igor K Oct 26 '10 at 23:18
0

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
  • 4,296
  • 1
  • 20
  • 29
  • Thanks, tried this and get an error:l->table CXX0030: Error: expression cannot be evaluated – Igor K Oct 26 '10 at 10:01
  • Any idea why this isn't working? The VS 2010 debugger breaks on Node* node = l->table[i]; – Igor K Oct 26 '10 at 10:58
  • 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 Oct 26 '10 at 11:25
  • Thanks @Flinsch, I put that line in immediately before the Node* node = ... line and it still broke on the Node* node = ... line! – Igor K Oct 26 '10 at 16:25
  • 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 Oct 28 '10 at 11:35