Thread: array type flexible array?

  1. #1
    Registered User
    Join Date
    Nov 2011
    Posts
    11

    array type flexible array?

    I'm trying to set up a simple array type that is aware of its size in C. "Flexible arrays" seemed at first glance to be the solution, but I ran into problems. Here's what I've got so far.

    Code:
    typedef struct
    {
        int elements;
        int keys[];
    } key_enum;
    
    const key_enum u_keys = { 4, {KEY_UP,    'k', 'K', '8'} };
    const key_enum d_keys = { 4, {KEY_DOWN,  'j', 'J', '2'} };
    const key_enum l_keys = { 4, {KEY_LEFT,  'h', 'H', '4'} };
    const key_enum r_keys = { 4, {KEY_RIGHT, 'l', 'L', '6'} };
    const key_enum q_keys = { 3, {KEY_ESC,   'q', 'Q'} };
    It seems to work until q_keys, where keys[] is a different size from the rest. Can someone point me in the right direction to a correct implementation of what I'm trying to do here?

  2. #2
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    None of that does what you want. To use "Flexible arrays" you need to actually use malloc for the memory allocation, and you cannot store the values into the array using initialisation syntax when doing this.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  3. #3
    Registered User
    Join Date
    Nov 2011
    Posts
    11
    Hmm. Well, what's the best practice for getting this effect in C?

  4. #4
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    The easiest way would be to just make the array big enough to hold the longest array you'll be storing in it. The downside, of course, is wasted space.

    If you're using C99 (which it seems you are since you're willing to use flexible array members), you can use compound literals:
    Code:
    typedef struct
    {
      int elements;
      int *keys;
    } key_enum;
    
    const key_enum u_keys = { 4, (int[]){KEY_UP,    'k', 'K', '8'} };
    Note, however, that the pointer to this compound literal becomes invalid after the scope in which it was declared is destroyed. That is, you cannot create this struct in a function and then return it, because the "keys" pointer will point to garbage. On the other hand, if this is done globally, the pointer will be valid for the lifetime of the program.

    With C99, you can use the fact that macros can accept variable argument lists to get the compiler to make sure that "elements" always contains the proper value, too:
    Code:
    #define MAKE_KEY(name, ...) const key_enum name = { sizeof (int[]){__VA_ARGS__} / sizeof(int), (int[]){__VA_ARGS__} }
    MAKE_KEY(u_keys, KEY_UP,    'k', 'K', '8');
    This has the decided advantage of preventing you from entering the wrong value for "elements", but it might be considered ugly...

    If you need the array (which, technically, keys won't be now since it's a pointer) to exist for the lifetime of the program but be created inside of a function, you'll need malloc().

  5. #5
    Registered User
    Join Date
    Nov 2011
    Posts
    11
    Hmm, using the above solution, I'm still getting the error "initializer element not constant" for q_keys.

  6. #6
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Quote Originally Posted by AaronP View Post
    Hmm, using the above solution, I'm still getting the error "initializer element not constant" for q_keys.
    Are you sure you're using a C99 compiler?

  7. #7
    Registered User
    Join Date
    Nov 2011
    Posts
    11
    I'm using gcc with -std=c99.


    EDIT: It compiles with clang, though. :/
    Last edited by AaronP; 12-11-2011 at 09:45 PM.

  8. #8
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Just make the array size as big as you need it in the worst case.
    You have Gigabytes to play with, it's not like using an extra few hundred bytes is going to make the slightest difference.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  9. #9
    Registered User
    Join Date
    Oct 2011
    Posts
    23
    I think that you will find these articles useful. They are about an array structure that uses dynamic allocation.
    Dystopian Code: Defining a Numeric Array Structure in C
    Dystopian Code: Dynamic Multidimensional Arrays in C

  10. #10
    Registered User
    Join Date
    Jun 2010
    Posts
    53
    AaronP,

    In C you don't really have the possiblilty to use flexible arrays. You may however, use malloc, to malloc the keys array to heap. Then realloc / calloc to store new values or more/less values to the array.

    regards
    r

  11. #11
    Registered User
    Join Date
    Nov 2011
    Posts
    11
    Well I'm declaring a set of constant arrays in a header, so I don't want to use malloc. I'm just looking for a good way to store the arrays size within the data so I can pass it to a function without any extraneous size variables. I don't make the arrays all the same size because the extra elements would be initialized to 0, which is the same as '\0'. I don't know if the ncurses function getch() can return 0, but I didn't want to take any chances.

    I could easily store it in the first element of the array, I suppose, but that didn't seem like it would be the best solution. cas's idea seems to work as far as c99 goes. I'm assuming in this case clangs compliance is better than gcc's?

  12. #12
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    I'm assuming in this case clangs compliance is better than gcc's?
    Interesting; neither of my gcc versions (4.6.2 and 3.4.6) complains. It also works with tcc, pcc, icc, Open64, and Solaris Studio. It's possible your gcc version has a bug.

  13. #13
    Registered User
    Join Date
    Nov 2011
    Posts
    11
    Perhaps. I'm using the binary in the Arch Linux (i686) repos. Thanks for the help, though.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 05-23-2011, 02:04 PM
  2. Flexible Array Size / Realloc
    By Prodiga1 in forum C Programming
    Replies: 5
    Last Post: 03-23-2011, 11:07 AM
  3. error: array type has incomplete element type
    By gerger in forum C Programming
    Replies: 8
    Last Post: 10-05-2010, 07:40 AM
  4. memory allocation for flexible array member of struct
    By jcarouth in forum C Programming
    Replies: 3
    Last Post: 09-11-2005, 12:19 PM
  5. flexible array member not at end of struct
    By krappa in forum C Programming
    Replies: 13
    Last Post: 05-14-2004, 01:36 PM