简体   繁体   中英

Declare array in struct

I am trying to make a struct for a circular buffer that contains an array of type "quote." However, the quote array must start out at a size of 10. I am trying to figure out if I declare the size of 10 in my .h file or in my .c file. My two files are as follows:

.h file:

typedef struct{
    unsigned int time;
    double rate;

}quote;

typedef struct{

    unsigned int testNum;
    quote quoteBuffer[];

}cbuf;

cbuf* cbuf_init();

.c file:

cbuf* cbuf_init(){

    cbuf *buffer = (cbuf *)calloc(1,sizeof(cbuf));
    buffer->testNum = 1;
    quote newQuote = {1,1.00};
    buffer->quoteBuffer[1] = newQuote;
    return buffer;


}

These are obviously just test values, however if I wanted to specifically make the quote array in the cbuf struct start out at a size of 10, would I declare that in the .h file as:

typedef struct{

    unsigned int testNum;
    quote quoteBuffer[10];

}cbuf;

or in the .c file some other way?

There are two ways of having dynamic arrays in structures. The obvious is of course to have it as a pointer, and dynamically allocate (or reallocate) when needed.


The other is to have an array of size 1, and then allocate a larger size than the structure, to accommodate for the array:

typedef struct {
    unsigned int testNum;
    quote quoteBuffer[1];
} cbuf;

cbuf *cbuf_init(const size_t num_quotes) {
    /* Allocate for the `cbuf` structure, plus a number of `quote`
     * structures in the array
     */
    cbuf *buffer = malloc(sizeof(cbuf) + (num_quotes - 1) * sizeof(quote));

    /* Other initialization */

    return buffer;
}

/* If more quotes are needed after initial allocation, use this function */
cbuf *cbuf_realloc(cbuf *buffer, const size_t new_num_quotes) {
    buffer = realloc(buffer, sizeof(cbuf) + (new_num_quotes - 1) * sizeof(quote));

    /* Other initialization */

    return buffer;
}

Now you can use the array as a normal array:

cbuf *buffer = cbuf_init();
buffer->quoteBuffer[5].time = 123;

Note: I only allocate extra space for 9 quote structures, but state that I allocate ten. The reason is that the cbuf structure already contains one quote structure in its array. 1 + 9 = 10. :)

Note 2: I put the quote array in the cbuf structure with one entry already in it for backwards compatibility. Having an array without a size in the structure is quite new in the C world.

you can also do this if you want 10 quotes in a cbuf but a statically allocated like quote buffer[10] would work too:

cbuf* cbuf_init(int numQuotes)
{
    cbuf *b = calloc(1, sizeof(cbuf) + numQuotes * sizeof(quote));

    return b;
}

If you want a statically sized circular buffer then your could declare the size in the header file. Using a #define for the buffer size will make the code more readable and maintainable, as you'll reference the size elsewhere in your code.

If you want the circular buffer to be growable then define the size in your C file. You'll then have to take care of tracking the size and destroying the memory that you will have to allocate dynamically.

In your example, I think you need to allocate more room for your quote structs...

cbuf *buffer = (cbuf *)calloc(1,sizeof(cbuf) + NUM_QUOTES*sizeof(struct quote));
                                             ---------------------------------

The reason for this is that in your struct def...

quote quoteBuffer[];

... quoteBuffer doesn't add size to the struct. quoteBuffer will point to one byte past the end of the struct, hence the need to allocate memory for the struct + memory for the array.

EDIT: Daniel Fischer's comment (thanks Daniel) - quoteBuffer may, in some cases, add size to the struct if it introduces padding. The reason is that the compiler will probably strive to get the most optimal alignment for quoteBuffer. For example, ints normally aligned of 4-byte boundaries. Eg a struct like:

struct {
   char a;
   int b;
}

is probably changed by compiler to

struct {
   char a;
   char pad[3]; // compiler adds padding behind the scenes 
   int b; // align b on a 4-byte boundary
}

This probs doesn't apply in your case as your struct leaves quoteBuffer[] on a 4 byte boundary.

The reason that the compiler does this is two fold. 1. On some architectures (not so common nowadays I think?), unaligned accesses aren't supported. 2. Aligned accesses are more efficient, even if architecture allows non-aligned accesses as it is one memory read as opposed to two memory reads plus a manipulation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM