datenhamster
datenhamster

Reputation: 31

Return structure with flexible array member

I need to return a structure with a flexible array member from a C function but can't figure out why it doesn't compile. I know that returning arrays can be achieved by encapsulating them in a struct as follows:

struct data_array {
    long length;
    double data[];
};

My function looks like this:

struct data_array test (int length) {
    struct data_array a;
    double* b = malloc (1000);
    a.length = 1000;
    a.data = b;
    return a;
}

However, the compiler returns: "invalid use of flexible array member".

According to the book "21st Century C", the data array in the struct is handled as a pointer (which makes perfectly sense to me). It has not been initialized and therefore there should be no memory been allocated for it to hold its data. (even the compiler doesn't know how much memory is needed for it). So I have to allocate the memory and assign it to my return variable.

So, why does the compiler returns an error? And how can I solve this problem?

Upvotes: 2

Views: 2130

Answers (7)

Eric Postpischil
Eric Postpischil

Reputation: 223633

You may either declare data to be an incomplete array (an array without specified dimension) or declare it to be a pointer. (An incomplete array inside a struct must be the last member and is called a flexible array member.)

If you declare it to be an incomplete array, then the structure essentially contains the length element and as many array elements as you allocate for it. You must allocate it with the base size of the structure plus space for all the elements, as with:

struct data_array *b = malloc(sizeof *b + NumberOfElements * sizeof *b->data);

However, you should not return a structure allocated in this way, because there is no way to return the extra elements of the flexible array—the return type of a function would include only the base size of the structure. However, you could return a pointer to the structure. So, you could return b but not *b.

If you declare data to be a pointer, then you create the structure and separately allocate space for data to point to, as with:

struct data_array b;
b.length = NumberOfElements;
b.data = malloc(NumberOfElements * sizeof *b.data);

Here are code samples. First, with a flexible array member:

struct data_array
{
    long length;
    double data[];
};

struct data_array *test(size_t NumberOfElements)
{
     struct data_array *b = malloc(sizeof *b + NumberOfElements * sizeof *b->data);
     // Put code here to test the result of malloc.
     b->length = NumberOfElements;
     return b;
}

Or with a pointer:

struct data_array
{
    long length;
    double *data;
};

struct data_array test(size_t NumberOfElements)
{
     struct data_array b = { NumberOfElements,
         malloc(sizeof *b + NumberOfElements * sizeof *b->data) };
     // Put code here to test the result of malloc.
     return b;
}

Upvotes: 4

Lidong Guo
Lidong Guo

Reputation: 2857

I use gcc and I think may be this way is ok:

struct data_array {
    long length;
    double* data;
};
struct data_array* test (int length) {
    struct data_array* a =(struct data_array *) malloc (sizeof (data_array));
    a->data = malloc (length*sizeof(double));
    a->length = length;
    return a;
}

Upvotes: 0

Chinna
Chinna

Reputation: 4002

you are trying to change base address of the array at line

a.data = b;

It is not possible to modify the array base address, array base address is a constant pointer.

Upvotes: 0

Ingo Leonhardt
Ingo Leonhardt

Reputation: 9904

Structs with flexible array members like yours (where the size of data is not given in the struct definition) are to be allocated like that:

struct data_array *a;   // pointer!!
a = malloc( sizeof(struct data_array) + 1000 * sizeof(double) );

Where sizeof(struct data_array) is the constant size of your struct excluding data and 1000 is the desired array size. Of course changing data to be a pointer and allocating it seperately will also work, but that is something slightly different.

Upvotes: 0

Ran Eldan
Ran Eldan

Reputation: 1350

Few things:

1) change the struct defenation to:

 struct data_array {
    long length;
    double* data;
          ^
};

2) This is how you should use malloc to allocate memory for your array:

a.data =  malloc (length * sizeof(double));

EDIT

There are too many mistakes, just follow this code:

#include <stdio.h>
#include <stdlib.h>
struct data_array {
    long length;
    double* data;
};
struct data_array* test (int length) {
    struct data_array* a;
    a = malloc (sizeof (data_array));
    a->data = malloc (length*sizeof(double));
    a->length = length;
    return a;
}

int main () {
    data_array* x;
    x = test (5);
    for (int i=0; i<5; i++) {
        x->data[i] = i+0.5;
    }
    for (int i=0; i<5; i++) {
        printf ("%f\n" , x->data[i]);
    }
}

NOTE that you might need to add casting to the types when useing maloc (my visual force me to do so, otherwise it's compile error. But it simply worng).

Upvotes: 0

BLUEPIXY
BLUEPIXY

Reputation: 40145

struct data_array * test(long length) {
    struct data_array *a = calloc(1,sizeof(struct data_array) + length*sizeof(double));
    a->length = length;
    return a;
}

Upvotes: 0

Annie Kim
Annie Kim

Reputation: 905

As to the reason why you cannot convert double* to double[], you may refer to this question that was asked before.

As to solve the problem, changing double data[]; to double *data; will work.

New UPDATE:

double* b = malloc(sizeof(double) * 1000);

Upvotes: 0

Related Questions