Return structure with flexible array member

2020-03-27 17:41发布

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?

7条回答
该账号已被封号
2楼-- · 2020-03-27 18:11

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.

查看更多
干净又极端
3楼-- · 2020-03-27 18:18

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).

查看更多
叼着烟拽天下
4楼-- · 2020-03-27 18:19
struct data_array * test(long length) {
    struct data_array *a = calloc(1,sizeof(struct data_array) + length*sizeof(double));
    a->length = length;
    return a;
}
查看更多
我命由我不由天
5楼-- · 2020-03-27 18:19

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.

查看更多
家丑人穷心不美
6楼-- · 2020-03-27 18:20

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);
查看更多
放荡不羁爱自由
7楼-- · 2020-03-27 18:29

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;
}
查看更多
登录 后发表回答