Advent of Code utility functions
As well as code specific to each solution, some utility functions are useful for common tasks in Advent of Code.
Reading input
Every puzzle provides a user-specific input, which is always ASCII text and is the same for both parts each day. The first step of any solution is to read this input into a string (an array of char
in C) so that it can be parsed into data structures (or, in early solutions, used directly).
Although we could read the input one line at a time, as the input is small (never more than 50KB, and usually much less), we can and should read the entire file at once.
One immediate design decision we need to make is: who should be responsible for allocating memory to hold the input string, the code that calls the 'read file' function or the function itself?
Read file function
The function that reads the file can work out exactly how much memory is required as the file is read. Either the file can be read once to get its size, and then read again into a buffer of exactly the same size (plus 1 element to store the terminating \0
), or an initial buffer can be allocated and then grown as the file is read. This allocation would have to be done on the heap with calloc
(and realloc
if grown), and the function would return a pointer to the start of the data. However, the disadvantage of this approach is that it breaks the allocate / free memory pairing, because the function is responsible for allocation but its caller is responsible for freeing the memory (and indeed all management other than allocation).
Code that calls the read file function
The read file function could accept a buffer parameter, which would be a pointer to a block of memory allocated by the calling code. This keeps the allocation and freeing of memory paired, as the caller manages both. However, the calling code does not have access to the file and therefore cannot easily decide how much memory to allocate. The calling code may have application-specific knowledge about approximate file sizes, and could then create a buffer large enough for most cases. This works in Advent of Code, where the file input unlikely to be more than 50KB (a reasonable buffer size on most systems - we are not allocating 4GB buffers).
If the calling code has no approximation of the file size, then it could call a function to calculate the file size and allocate a buffer based on that. This does create a timing problem though, as the file could increase in size between the size being calculated and the buffer being filled. This would not be a problem for Advent of Code input, which never changes for a given puzzle and user, but it would be an unacceptable risk when reading log files that are written to frequently.