The usual approach is to allocate some amount of space at first (large enough to cover most of your cases), then double it as necessary, using the realloc
function.
An example:
#define INITIAL_ALLOCATED 32 // or enough to cover most cases
...
size_t allocated = INITIAL_ALLOCATED;
size_t size = 0;
...
int *a = malloc( sizeof *a * allocated );
if ( !a )
// panic
int val;
while ( fscanf( in, "%d", &val ) == 1 )
{
if ( size == allocated )
{
int *tmp = realloc( a, sizeof *a * allocated * 2 ); // double the size of the buffer
if ( tmp )
{
a = tmp;
allocated *= 2;
}
else
{
// realloc failed - you can treat this as a fatal error, or you
// can give the user a choice to continue with the data that's
// been read so far.
}
a[size++] = val;
}
}
We start by allocating 32 elements to a
. Then we read a value from the file. If we're not at the end of the array (size
is not equal to allocated
), we add that value to the end of the array. If we are at the end of the array, we then double the size of it using realloc
. If the realloc
call succeeds, we update the allocated
variable to keep track of the new size and add the value to the array. We keep going until we reach the end of the input file.
Doubling the size of the array each time we reach the limit reduces the total number of realloc
calls, which can save performance if you're loading a lot of values.
Note that I assigned the result of realloc
to a different variable tmp
. realloc
will return NULL
if it cannot extend the array for any reason. If we assign that NULL
value to a
, we lose our reference to the memory that was allocated before, causing a memory leak.
Note also that we check the result of fscanf
instead of calling feof
, since feof
won't return true
until after we've already tried to read past the end of the file.