C:如何以更干净的方式将null终止符复制到结构成员?

时间:2011-05-04 12:05:22

标签: c string null strcpy

基本上我正在对字符串进行标记,并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终止。你有什么建议或做法吗?

4 个答案:

答案 0 :(得分:3)

两件事:

  1. 请注意strncpy()具有非常意外的语义,如果没有完全被字符串填充,它将始终为0填充缓冲区,如果它完全填充缓冲区,它将不会终止字符串。这两个都很奇怪,我建议不要使用它。
  2. 永远不要使用它的大小索引数组,就像stringID[ID_SIZE]似乎正在做的那样;那是出界的。
  3. 最好的解决方案是编写一个不那么奇怪的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)函数。如果你有一个可以放入它的库,这种方法非常有效。使用它也需要最少的代码更改。

我并不热衷于宏方法,因为有人会将指针传递给错误的宏。