基本上我正在对字符串进行标记,并strncpy
找到结构成员的字符串,即stringid。它当然遇到了终止不足的问题,我为它添加了额外的数组空间,我不知道如何正确添加它。
我这样做了:
my_struct[iteration].stringID[ID_SIZE-1] = '\0' //updated
我不确定这是否真的有效,它看起来很可怕IMO。
Str(n)表示空字符或0,会导致GCC和MinGW生成警告:
warning: null argument where non-null required (arg 2)
我是否对如何以干净的方式做到这一点视而不见?我想将成员数组memset到全零,然后复制字符串以很好地适应null终止。你有什么建议或做法吗?
答案 0 :(得分:3)
两件事:
strncpy()
具有非常意外的语义,如果没有完全被字符串填充,它将始终为0填充缓冲区,如果它完全填充缓冲区,它将不会终止字符串。这两个都很奇怪,我建议不要使用它。stringID[ID_SIZE]
似乎正在做的那样;那是出界的。最好的解决方案是编写一个不那么奇怪的strncpy()
自定义版本,或者(如果知道输入的长度)只使用strcpy()
。
UPDATE :如果输入令牌的长度是静态的,但由于您的令牌化过程,它们在源缓冲区中没有以0结尾,那么只需使用memcpy()
和手动终止:
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';
我认为不需要在宏中“包装”上述内容。
答案 1 :(得分:1)
实际上,null终止你建议的方式并不可怕,我个人非常喜欢它。
在我看来,最好的方法是将它定义为类似方式的宏:
// 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';
然后,您可以根据需要在代码周围使用它。
在Windows上,Microsoft为您提供以下函数,这些函数在复制字符串时终止null:StringCchCopy
答案 2 :(得分:0)
正如其他人所说,strncpy
具有奇怪的语义。执行有限字符串复制的惯用方法是将strncat
写入空字符串:
my_struct[iteration].stringID[0] = '\0';
strncat(my_struct[iteration].stringID, src, ID_SIZE-1);
这总是附加一个终止NUL,(并且最多填充ID_SIZE字符,包括NUL)。
答案 3 :(得分:0)
我最终写了一个强制NULL终止的strncpyz(char * pszTo,char * pszTo,size_t lSize)函数。如果你有一个可以放入它的库,这种方法非常有效。使用它也需要最少的代码更改。
我并不热衷于宏方法,因为有人会将指针传递给错误的宏。