I ve written a simple library file with a function for reading lines from a file of any size. The function is called by passing in a stack-allocated buffer and size, but if the line is too big, a special heap-allocated buffer is initialized and used to pass back a larger line.
This heap-allocated buffer is function-scoped and declared static, initialized to NULL at the beginning of course. I ve written in some checks at the beginning of the function, to check if the heap buffer is non-null; if this is the case, then the previous line read was too long. Naturally, I free the heap buffer and set it back to NULL, thinking that the next read will likely only need to fill the stack-allocated buffer (it should be very rare to see lines over 1MB long, even in our application!).
I ve gone over the code and tested it fairly thoroughly, both by reading it carefully and by running a few tests. I am reasonably confident that the following invariant is maintained:
- The heap buffer will be null (and will not leak any memory) on function return if the stack buffer is all that is needed.
- If the heap buffer is not null, because it was needed, it will be freed on the next function call (and possibly reused if needed on that next line).
But I ve thought of a potential problem: If the last line in a file is too long, then since the function is presumably not called again, I m not sure I have any way to free the heap buffer-- it is function-scoped, after all.
So my question is, how do I go about freeing dynamically allocated memory in a function-scoped static pointer, ideally without calling the function again? (And ideally without making it a global variable, either!)
Code available on request. (I just haven t got access now, sorry. And I m hoping the question is sufficiently general and well-explained for it not to be needed, but by all means feel free to disabuse me of that notion!)
EDIT: I feel I should add a couple of notes about the usage of the function.
This particular function is used in the form of lines being read serially from a file, and then immediately copied into POD structs, one line per struct. Those are created on the heap as the file is read, and each one of those structs has a char pointer containing (a cleaned up version of) a line from the file. In order for these to persist, a copy already has to occur. (That was one of the big counterarguments brought up in many of the answers-- oh no, the line needs to be COPIED, oh dearie me).
As for multithreading, as I said this is designed to be used serially. No, it isn t thread safe, but I don t care.
Thanks for the multitude of responses, though! I ll read them more thoroughly when I get time. Currently, I m leaning towards either passing an extra pointer around or redesigning the function so that when fgets
shows EOF, then I might just build the freeing logic there instead and the user hopefully won t need to worry about it.