Hi all,
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.