39

I am wondering why I keep getting error: flexible array member not at end of struct error when I call malloc. I have a struct with a variable length array, and I keep getting this error.

The struct is,

typedef struct {
  size_t N;
  double data[];
  int label[];
} s_col; 

and the call to malloc is,

col = malloc(sizeof(s_col) + lc * (sizeof(double) + sizeof(int)));

Is this the correct call to malloc?

octopusgrabbus
  • 10,555
  • 15
  • 68
  • 131
csta
  • 2,423
  • 5
  • 26
  • 34

3 Answers3

40

You can only have one flexible array member in a struct, and it must always be the last member of the struct. In other words, in this case you've gone wrong before you call malloc, to the point that there's really no way to call malloc correctly for this struct.

To do what you seem to want (arrays of the same number of data and label members), you could consider something like:

struct my_pair { 
    double data;
    int label;
};

typedef struct { 
   size_t N;
   struct my_pair data_label[];
};

Note that this is somewhat different though: instead of an array of doubles followed by an array of ints, it gives you an array of one double followed by one int, then the next double, next int, and so on. Whether this is close enough to the same or not will depend on how you're using the data (e.g., for passing to an external function that expects a contiguous array, you'll probably have to do things differently).

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 1
    Oddly, this up-voted answer does not well answer the question: “What is the cause…” It states a rule (a flexible array member can only be last), but it does not give a source for the rule (C 2011/2018 6.7.2.1 18) or a reason (the locations of later members could not be determined since the since of the flexible array is not known to the compiler). – Eric Postpischil Sep 07 '20 at 14:38
  • 2
    @EricPostpischil: Somebody who's starting with a struct declaration with two flexible array members just needs to realize that's not allowed, not a citation of the specific part of the standard that prohibits it. Believe me, I've cited the standard *plenty* of times when it made sense (feel free to look through my posts if you don't believe that). But I'm quite certain that doing so in this case would only distract, not inform. – Jerry Coffin Sep 08 '20 at 03:18
14

Given a struct definition and a pointer to the start of a struct, it is necessary that the C compiler be able to access any member of the struct without having to access anything else. Since the location of each item within the structure is determined by the number and types of items preceding it, accessing any item requires that the number and types of all preceding items be known. In the particular case where the last item is an array, this poses no particular difficulty since accessing an item in an array requires knowing where it starts (which requires knowing the number and type of preceding items, rather than the number of items in the array itself), and the item index (which the compiler may assume to be smaller than the number of items for which space exists, without having to know anything about the array size). If a Flexible Array Member appeared anywhere other than at the end of a struct, though, the location of any items which followed it would depend upon the number of items in the array--something the compiler isn't going to know.

supercat
  • 77,689
  • 9
  • 166
  • 211
4
typedef struct {
  size_t N;
  double data[];
  int label[];
} s_col; 

You can't have flexible array member (double data[]) in the middle. Consider hardcoded array size or double *data

J-16 SDiZ
  • 26,473
  • 4
  • 65
  • 84
  • I dont understand, I'm taught that "T* var" is the same as "T var[]" – luke1985 Mar 21 '14 at 14:09
  • 2
    @lukasz1985: What you say is sort of true in context of a function argument, where you can specify "an array manipulating argument" which is technically implemented by means of a pointer. Normally (i.e. here) array is an array, and pointer is a pointer. – stan423321 Apr 12 '14 at 19:55