10

I'm beginning to learn about the use of structs in C. It's challenging and enjoyable. Needless to say I've encountered a problem I can't seem to figure out. I'm trying to make a flexible struct array as a member of another struct but I'm getting an error:

invalid use of flexible array

What am I doing wrong?

#define NUM_CHANNELS 4

struct channelStruct {
    float volume;
    uint mute;
};


struct enginestruct
{
    float bpm;
    int synctimeinbeats;
    int synctimeinsamples;
    int currentbeat;
    int oneBeatInSamples;
    int samplerate;
    struct channelStruct channels[];
};

struct enginestruct engine, *engineptr;
struct channelStruct  channel, *channelptr;        


-(void) setupengine


{
    engineptr = &engine;
    engineptr->oneBeatInSamples = 22050;
    engineptr->samplerate = 44100;

    struct channelStruct *ch = (struct channelStruct *) malloc ( 
        NUM_CHANNELS*sizeof(struct channelStruct) );
    //error occurs here
    engineptr->channels = ch;
}

EDIT 1

It's something like this I am trying to achieve

flexible length struct array inside another struct using C

EDIT 2*

O.K so I seem to be approaching the creation of a variable sized array of struct the wrong way. I have 2 things that I'm trying. The first I know works for sure. The second I would just like if somebody could sanity check it for me. I'm still learning about pointers and would like to know if A is the same as B. B would be my preferred method but I don't know if its correct. I'm confident about a because when I debug channels i see channel[0],channel[1]channel[2] etc. But I'm not so confident about B because when I debug it I only see an address to memory and the variables of channel struct listed.

A

// pretty sure this is o.k to do but I would prefer 
// not to have to set the size at compile time.

struct enginestruct
{
    float bpm;
    int synctimeinbeats;
    int synctimeinsamples;
    int currentbeat;
    int oneBeatInSamples;
    int samplerate;
    channel channels[NUM_CHANNELS]; //is this technically a pointer?
};

B

//I'm not sure if this is valid. Could somebody confirm for me if 
//it is allocating the same amount of space as in A.

struct enginestruct
{
    float bpm;
    int synctimeinbeats;
    int synctimeinsamples;
    int currentbeat;
    int oneBeatInSamples;
    int samplerate;
    channel *channels;
};

//This only works if channel in the engine struct is defined as a pointer.
channel * ar = malloc(sizeof(*ar) * NUM_CHANNELS);
engineptr->channels = ar;

**EDIT 3****

Yep they are the same. Not sure when you would use one over the other tho

channel channels[NUM_CHANNELS]; 

Is Equal To :)

struct enginestruct
{
    float bpm;
    int synctimeinbeats;
    int synctimeinsamples;
    int currentbeat;
    int oneBeatInSamples;
    int samplerate;
    channel *channels;
};

channel * ar = malloc(sizeof(*ar) * NUM_CHANNELS);
engineptr->channels = ar;
Community
  • 1
  • 1
dubbeat
  • 7,706
  • 18
  • 70
  • 122

2 Answers2

19

Edit

I think I remember now what the problem is. When you declare a struct with a flexible array as it's last member it's doing something completely different than what you think.

struct channelStruct channels[];

is NOT a pointer, it is an in place array which is contiguous with the struct.

The way this is intended to be used is to lay the struct over an existing block memory. For instance, this is useful in networking when you have a packet with variable length data. So you might do something like:

struct mydata {
    // various other data fields
    int varDataSize;
    char data[];
}

When you receive a packet you cast a pointer to the data to a mydata pointer and then the varDataSize field tells you how much you've got. Like I said, the thing to remember is that it's all one contiguous block of memory and data is NOT a pointer.

Old Answer:

I think that's only allow in the C99 standard. Try compiling with the -std=c99 flag.

Also, see this thread, Variable array in struct

Also see this SO post: Flexible array members in C - bad?

Community
  • 1
  • 1
Robert S. Barnes
  • 39,711
  • 30
  • 131
  • 179
  • setting that flag didnt seem to rid me of the error. I'm having a read through the links. – dubbeat Dec 07 '10 at 17:54
  • hmmmmm. thats very difficult to get my head around. Could you point me in the right direction of an example illustrating the said packet example?Also would it be safe to assume that this flexible array method is not suitable for struct types or is it just the way I'm trying to do it? – dubbeat Dec 07 '10 at 22:48
  • @dubbeat: It's no problem to have a variable array of structs inside another struct. Just remember that var array has to be the last member of the outer struct, and that only the outer most struct can have a variable array. Look at the format for a TCP packet, it's a perfect example: http://www.networksorcery.com/enp/protocol/tcp.htm If you still don't understand, let me know and maybe I can write up a more in depth example later tonight. – Robert S. Barnes Dec 08 '10 at 06:25
  • @dubbeat: Another suggestion, it seems like you don't really need to use a variable array, why don't you just use a pointer in enginestruct? That will immediately solve your problem. – Robert S. Barnes Dec 08 '10 at 06:30
  • @Robert. Could you take a look at my "edit 2 method B" and let me know if its valid? – dubbeat Dec 08 '10 at 11:28
0

I am not an expert in this C feature but my common sense tells me that you cannot define objects of the type struct enginestruct, only pointers. This regards the engine variable in the following line:

struct enginestruct engine,*engineptr;
anatolyg
  • 26,506
  • 9
  • 60
  • 134
  • 1
    of course you can define objects of the type struct -what it is- – dubbeat Dec 07 '10 at 18:20
  • if you can define it, what size does it have(the compiler needs to know this in order to put it in a struct or on the stack)? I'm guessing that if it can be defined, the array part will be of size 0, so it won't be very useful. – Bwmat Dec 07 '10 at 23:00