I'm trying to understand how to think about memory allocation from a practical perspective. I think I understand how to implement malloc
and realloc
in a basic sense, but I don't understand how to do it efficiently.
The examples I have in my books and online references, all show realloc
being used within a loop, such as to increase the length of an array. I don't know enough to be sure but it appears that that approach may not be very efficient.
For example, in the test code below, a JSON string is being built to pass the file name, size, and date last modified to another application. It's not known in advance how many files are in the directory or the size of the data elements. I realize this is simple, but I have a similar issue in building a JSON string of SQLite result rows when the number of rows and their sizes are not known in advance. This file information code example is simpler to follow but the more important task is the SQLite data.
In the code below, an opening piece of JSON is written to the character array json
, then each piece of file information is written in the while
loop, after which the JSON string is closed. All is written using snprintf
.
Right now, json
is arbitrarily set to length 1000; and the code does produce a properly formed JSON string of this data, so long as it fits.
My question is, should realloc()
really be used in each iteration of the while
loop to extend the size of json
once the size of the next data to be written is known? Or, is realloc()
a bit of work, and it would be better to allocate a larger block of memory at the start and then extend that with another larger block once the remaining space in json
reaches a minimum or snprintf
returns a value indicating a write truncation, such that there are fewer calls to realloc()
?
How is this done in "real life" rather than examples in books for illustration?
Thank you.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
void read_dir_1 ( char *, char * );
int main( void )
{
read_dir_1( "c", "./SQLite3/" );
return 0;
}
void read_dir_1 ( char *ext, char *path )
{
DIR *dp;
struct dirent *ep;
struct stat info;
int rc, q, i, l;
char *t;
char fl_name[ 400 ];
char json[ 1000 ]; // Temporary value.
dp = opendir( path );
if ( dp != NULL )
{
i = 0;
q = 0;
l = sizeof( json ) - 1;
// Open the JSON string.
q = snprintf( json, l, "%s", "{\"c\":\"A\",\"d\":[" );
l -= q;
i += q;
while ( ep = readdir( dp ) )
{
rc = snprintf( fl_name,
sizeof( fl_name ) - 1,
"%s%s",
path,
ep->d_name
);
if ( ( rc = stat( fl_name, &info ) ) != 0 )
{
printf( "rc : %d\n", rc );
printf( "errno : %d, strerror : %s\n", errno, strerror( errno ) );
continue;
}
if ( ( info.st_mode & S_IFMT ) != S_IFREG )
continue;
t = strrchr( ep->d_name, '.' );
if ( !t || strcmp( ++t, ext ) != 0 ) continue;
q = snprintf( json + i,
l,
"%s%.*s%s%d%s%d%s",
"{\"n\":\"",
strlen( ep->d_name ) - strlen( ext ) - 1, ep->d_name,
"\",\"s\":",
info.st_size / 1024,
",\"d\":",
info.st_mtime,
"}," );
if ( q < 0 || q > l )
{
// Ran out of room in json to hold the file info.
printf( "Ran out of memory to store file info." );
//?????????? Better free all allocated memory before returning.
return;
}
i += q;
l -= q;
} // next while loop
// Close the JSON string. Overwrite the comma after the last object in the array "d".
q = snprintf( json + i - 1,
l,
"%s",
"]}" );
if ( q < 0 || q > l )
{
// Ran out of room in json to hold the file info.
printf( "Ran out of memory to store file info." );
//?????????? Better free all allocated memory before returning.
return;
}
printf( "JSON : %s", json );
closedir (dp);
}
else
{
perror ("Couldn't open the directory");
}
//?????????? Better free all allocated memory before returning.
return;
}