Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
The fundamental problem here is that it is already ambiguous where the "end" of the data in the buffer is. Strings can be empty (have zero length as reported by strlen); as such, buffer could equal...
Answer
#1: Initial revision
The fundamental problem here is that **it is already ambiguous** where the "end" of the data in the buffer is. Strings can be empty (have zero length as reported by `strlen`); as such, `buffer` could equally well be interpreted as containing *three* strings, where the last is empty. Or more than that - up to what the buffer can hold. **The situation is even worse if we start with uninitialized memory**; then there's no way to tell whether the byte after the last intentionally-written null is just uninitialized garbage, or the start of another actual string. If we don't need to be able to store empty strings, one way around the problem is to mimic how null-termination works, but at a string level rather than a byte level. That is to say, we can establish a convention that the sequence of strings is "empty-string-terminated", and use `strlen` repeatedly to search for this string. That will tell us where to copy the new string. However, it will be both simpler and more flexible to just ***remember* where the end of the string sequence is**, and update it whenever another string is added. For example, we could do this using an integer index: ``` /* the lengths of the two initial strings and their null terminators */ int used = 8; int usable = sizeof(buffer); strncpy(buffer + used, another_string, usable - used); buffer[usable - 1] = '\0'; used += strlen(another_string) + 1; if (used > usable) used = usable; ``` This code takes care of a few important issues. Note the pointer arithmetic: `buffer` decays to a pointer to the start of the array, so `buffer + used` is the desired destination pointer. We need to restrict `strncpy` to the amount of space that *remains in* the buffer - between `buffer + used` and the end of the buffer - to avoid writing beyond the end of the array. Note that `strncpy` avoids writing more than the declared amount of room, but *does not* null-terminate if it reaches that limit. To avoid ending up with non-null-terminated data at the end of the array, we can just unconditionally add a null to the last spot in the buffer each time, as shown. (A more sophisticated approach might detect this situation and report an error somehow.) After writing, we need to update the record of how much space is used. (When the buffer is full, `used` will be limited to the array length; future attempts at `strncpy` will see that zero bytes are available.) Also keep in mind that a representation like this is not convenient for *modifying* the strings later. In particular, anything that tries to change the length of a string that isn't at the end of the sequence, will cause a major headache - because every other string after it will need to be shifted around to make room or close a gap. (This is the same reason that you can't easily modify a single line of a text file "in place".)