Strncpy 只应与固定长度数组一起使用

Strncpy should only be used with fixed length arrays

根据 this Whosebug 评论 strncpy 永远不应与非固定长度数组一起使用。

strncpy should never be used unless you're working with fixed-width, not-necessarily-terminated string fields in structures/binary files. – R.. Jan 11 '12 at 16:22

我知道如果您为字符串动态分配内存是多余的,但是有没有理由使用 strncpy 而不是 strcpy

反对使用 strncpy 的论据是它不能保证您的字符串将以 null 结尾。

使用非固定长度数组时,在 C 语言中复制字符串的不太容易出错的方法是使用 snprintf,它可以保证字符串的空终止。

一个很好的 Blog Post 评论 *n* 函数。

These functions let you specify the size of the buffer but – and this is really important – they do not guarantee null-termination. If you ask these functions to write more characters than will fill the buffer then they will stop – thus avoiding the buffer overrun – but they will not null-terminate the buffer.

这意味着在不处理固定数组时使用 strncpy 和其他此类函数会引入非空终止字符串的不必要风险,这可能是代码中的定时炸弹。

strncpy 会将数据复制到您指定的限制 - 但如果它在字符串结束之前达到该限制,它将离开目标 unterminated.

也就是说strncpy有两种可能。一是你得到的行为与 strcpy 无论如何都会产生的完全一样(除了更慢,因为它用 NUL 填充了目标缓冲区的其余部分,而你实际上从未真正想要或关心过)。另一个是它产生的结果通常不能用于任何实际用途。

如果您想将最大长度的字符串复制到固定长度的缓冲区中,您可以(例如)使用 sprintf 来完成这项工作:

char buffer[256];

sprintf(buffer, "%255s", source);

strncpy 不同,此 总是 零终止结果,因此结果始终可用作字符串。

如果您不想使用 sprintf(或类似的),我建议您只编写一个函数来实际执行您想要的操作,一般顺序如下:

void copy_string(char const *dest, char const *source, size_t max_len) { 
    size_t i;
    for (i=0; i<max_len-1 && source[i]; i++)
        dest[i] = source[i];
    dest[i] = '[=11=]';
}

既然你已经将它标记为 C++(除了 C):我的建议是 通常 只需使用 std::string 就可以避免 C++ 中的整个混乱.

如果你真的必须在 C++ 中使用以 NUL 结尾的序列,你可能会考虑另一种可能性:

template <size_t N>
void copy_string(char const (&dest)[N], char const *source) {
    size_t i;
    for (i=0; i<N-1 && source[i]; i++)
        dest[i] = source[i];
    dest[i] = '[=12=]';
}

这仅在目标是实际数组(而非指针)时有效,但对于这种情况,它让编译器推导出数组的大小,而不是要求用户显式传递它。这通常会使代码更快一点(函数调用的开销更少)并且更难搞砸和传递错误的大小。

char * strncpy ( char * destination, const char * source, size_t num );

strncpy() 的局限性:

  1. 如果目标字符串已完全填充,则不会在目标字符串上放置空终止符。并且,如果源长于 num.
  2. ,则不会在目标末尾隐式附加空字符。
  3. 如果 num 大于源字符串的长度,目标字符串将用空字符填充到 num 长度。

和strcpy一样,它不是内存安全操作。因为它在复制源之前没有检查目标中是否有足够的 space,所以它是缓冲区溢出的潜在原因。

参考:Why should you use strncpy instead of strcpy?

我们有 2 个版本用于将字符串从一个版本复制到另一个版本 1> 结构化 2> 结构化 这两个版本用于固定和非固定长度数组。复制字符串时,strcpy 不检查目标字符串的上限,strncpy 会检查它。当目标字符串达到此上限时,函数 strncpy 将显示 return 错误代码,同时函数 strcpy 将对当前进程的内存产生一些影响并立即终止进程。这样 strncpy 比 strcpy

更安全