0

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?

5
  • What do you mean by "start out at a size 10"? Do you imply that you may wish to enlarge this array at the run-time? Commented Apr 29, 2013 at 8:33
  • when you provifde the definition of the struct only you should give the array its size, you cant have it empty. if you dont know the size that will be required then declare a pointer to that type and allocate the "array" on heap Commented Apr 29, 2013 at 8:34
  • 1
    buffer->quoteBuffer[1] = newQuote; in this code you are writing beyond the size of quoteBuffer which was zero. (See this answer on what a flexible array member is). Commented Apr 29, 2013 at 8:34
  • Also, you don't cast the result of malloc (or calloc) Commented Apr 29, 2013 at 8:36
  • yes I wish to be able to enlarge the size of the array at runtime. I realize that my current code is writing beyond the size of the quoteBuffer when it was zero, however this was just a test to see if the struct was working properly Commented Apr 29, 2013 at 8:40

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

6 Comments

In the typedef for the cbuf struct, you declare quoteBuffer as an array of size 1. Wouldn't this cause errors when trying to insert a quote object into the 3rd, 4th, etc spot? I realize you allocated memory for these 3rd, 4th, etc quotes, but the array was intialized without spaces for them, no?
@user2252004 Not if you allocate extra space for it, as shown in my example code.
Ah ok. So in C, if you allocate extra space for an array after you initialize it as a certain size, you can dynamically add/remove indices (spaces) from that array?
@user2252004 Well in a way, you still only have the space you allocated for it, in my example ten entries in the array. If you need to add more than those initial ten at a later time you could use realloc for it.
@user2252004 Just added a function to dynamically reallocate the cbuf structure.
|
1

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;
}

Comments

1

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. E.g. 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.

2 Comments

"quoteBuffer doesn't add size to the struct." It might be worth mentioning that it may cause padding to be included that wouldn't be present without the flexible array member.
@Daniel, yes good point, I hadn't thought of that... will add

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.