Question

Essentially I am tokenizing a string and strncpying the string found to a structure member, i.e. stringid. It of course suffers from the problem of lack of termination, I have added an extra array space for it, I've no clue how to add it properly.

I had done it like so:

my_struct[iteration].stringID[ID_SIZE-1] = '\0' //updated

I am unsure if that really works, it looks horrible IMO.

Str(n)cpying a null character, or 0, results in a warning generated by GCC and MinGW:

warning: null argument where non-null required (arg 2)

Am I blind on how to do this in a clean manner? I was thinking of memsetting the member array to all zeros, and then copying the string in to nicely fit with null termination. Do you have any suggestions or practises?

Was it helpful?

Solution

Actually, null terminating the way you suggested isn't horrible at all and I personally very much like it.

The best way, in my opinion, would be to define it as a macro in similar fashion:

// for char* blah;
#define TERMINATE_DYNAMIC_STRING(str, len) str[len] = '\0';
// for char mytext[] = "hello";
#define TERMINATE_STRING(str) str[sizeof(str)/sizeof(str[0]) - 1] = '\0';

Then you can use it all around your code as much as you want.

On Windows Microsoft gives you the following functions which null terminate when copying string: StringCchCopy

OTHER TIPS

Two things:

  1. Beware that strncpy() has very unexpected semantics, it will always 0-fill the buffer if not totally filled by the string, and it will not terminate the string if it completely fills the buffer. Both of these are weird enough that I recommend against using it.
  2. Never index an array with it's size, like stringID[ID_SIZE] seems to be doing; that is out of bounds.

The best solution is to write a custom version of strncpy() that is less weird, or (if you know the length of the input) just use strcpy().

UPDATE: If the length of your input tokens is static, but they're not 0-terminated in the source buffer due to your tokenization process, then just use memcpy() and manual termination:

const char * token = ...; /* Extract from tokenization somehow. Not 0-terminated. */
const size_t token_length = ... /* Perhaps from tokenization step. */
memcpy(my_struct[iteration].stringID, token, token_length);
my_struct[iteration].stringID[token_length] = '\0';

I don't see a need to "wrap" the above in a macro.

As others have noted, strncpy has odd semantics. The idiomatic way to do a bounded string copy is to strncat onto an empty string:

my_struct[iteration].stringID[0] = '\0';
strncat(my_struct[iteration].stringID, src, ID_SIZE-1);

This always appends a terminating NUL, (and fills at most ID_SIZE characters including the NUL).

I ended-up writing a strncpyz(char* pszTo, char* pszTo, size_t lSize) function that forces the NULL termination. This works pretty-well if you have a library to put it in. Using it also requires minimal code changes.

I'm not keen on the macro approach because somebody will pass a pointer to the wrong macro.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top