In this program I'm writing I want to pre-allocate space for a
indeterminate (but potentially large) number of instances of a
given structure. And if this amount of memory proves insufficient,
I'll add another large chunk with realloc. Etc.
So somewhere in my code I'll have an initial pre-allocation that
looks like
size_t _siz = INITIAL_SIZE;
Why are you using an identifier whose name violates 7.1.3?
foo* foos;
int next_slot = 0;
foos = (foo *)malloc(_siz);
Why are you using a meaningless cast?
While not incorrect, the more common idiom is to keep track of the
number of objects, not the total size they consume.
/* error check */
/* ... */
while (size <= next_slot * sizeof foo) {
foo is a type. When the operand of sizeof is a type, the parentheses
are required.
If the left operand equals the right operand, you will overflow your
allocated memory. You probably want <, not <=.
Did you mean _siz instead of size?
What will happen if you execute this block multiple times (think of
the wheat and chessboard fable)? You might want to consider
size += INITIAL_SIZE;
which will have the same effect on the first execution but result in a
significantly smaller number on subsequent executions.
foos = (foo *)realloc(foos, size);
If realloc fails, you have created a memory leak and cannot access any
of the previously created objects.
/* error check */
}
/* ... */
Is there a way to choose a good value for INITIAL_SIZE? Should I
just pick a number out of a hat? 101? 1001? 5091? Or should I
pick a "nice power of 2" out of a hat, like 1024 or 4096? Or is
there a better way?
Analysis is almost always superior to guessing.
Even if the exact number is unknown, do you know anything about the
number of objects you are likely to need? If you run the program
repeatedly, do you know anything about the distribution of this value?
Does you program spend most of its time processing the data (so that
minimizing calls to malloc might be useful) or is it I/O bound (in
which case it wouldn't matter if your call to realloc increased the
space for only one more object)?
Since INITIAL_SIZE is not the quantity of objects but the amount of
space they consume, it needs to be a multiple of sizeof(foo). If you
change the initialization of _siz to
INITIAL_SIZE * sizeof(foo)
(or change the argument to malloc) then your numbers above might be
reasonable.
Most systems today use a virtual memory model. Virtual memory is
allocated in terms of pages. Each page has a fixed size determined by
the operating system and hardware. There may be some benefit to
allocating memory in quantities that match page boundaries.
How sophisticated would you like your growth algorithm to be?
Increasing by a constant factor (such as your doubling) or by a
constant quantity (such as my suggestion) are dirt simple approaches.
There are others, such as increasing by 100%, 75%, 50%, and 25% for
the first four changes and then if more increases are needed start
raising the percentage again. If you are obtaining the data from a
file, you could use a system dependent method of getting the file size
and computing an initial estimate from that.