tags:

views:

39

answers:

4

I had a similar question here about allocating and initializing one pointer to struct in a subfunction. Unfortunately I can't extend the good solution I got there to initialize an array of structs. The first element is OK but the second (and all following) elements are zero/NULL.

Here is a commented example. Maybe someone can help me...

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

typedef struct {int n;} mystruct;

void alloc_and_init_array(mystruct **s)
{
    // create an array containing two elements
    *s = calloc(sizeof(mystruct), 2);
    (*s[0]).n = 100;
    (*s[1]).n = 200;
}

int main(void)
{
    mystruct *s; // only a pointer. No memory allocation.
    alloc_and_init_array(&s);

    printf("1st element: %d\n", s[0].n); // here I get 100, that's OK
    printf("2nd element: %d\n", s[1].n); // here I get 0. Why?

    return 0;
}
+1  A: 

You need some parentheses:

((*s)[1]).n = 200;
 ^ extra parentheses required

The subscript ([]) has higher precedence than the indirection (*) so without parentheses it is applied first.

You need to dereference s to get the array pointed to by it, then access the element at index one.

James McNellis
+1  A: 

In alloc_and_init_array the brackets are in the wrong place.

s is a pointer to the array of structs. So *s is the array of structs. Therefore (*s)[0] and (*s)[1] will give you the first and second struct in that array respectively.

So the two lines should be:

(*s)[0].n = 100;
(*s)[1].n = 200;
Richard Fearn
+1  A: 

You're invoking undefined behavior, [] has precedence over * . You'd want:

(*s)[0]).n = 100;
(*s)[1]).n = 200;
nos
Thanks everyone, guys! In desperation I alredy started to use something like "*ptr+sizeof(mystruct)*i". Your solutions are great.
ClosedID
+1  A: 

As a general rule for both clarity and to avoid the inevitable questions of precedence that follow the * operator around, I would do it something like this:

void alloc_and_init_array(mystruct **s)
{
    mystruct *p;
    // create an array containing two elements
    p = calloc(sizeof(mystruct), 2);
    if (p) {
        // initialize it if creation succeeded.
        p[0].n = 100;
        p[1].n = 200;
    }
    *s = p;
}

One subtle difference in what I've written is that I don't accidentally dereference a NULL pointer if the call to calloc() failed. Since s must be non-NULL, I'd be tempted to put assert(s) near the top of the function to document that and catch the can't-happen error.

RBerteig