Strncpy只能用于固定长度的数组

时间:2016-06-10 03:29:31

标签: c++ c strcpy strncpy

根据this StackOverflow注释strncpy不应该与非固定长度数组一起使用。

  除非您使用结构/二进制文件中的固定宽度,不一定终止的字符串字段,否则永远不应使用

strncpy。 - R .. 2012年1月11日16:22

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

4 个答案:

答案 0 :(得分:3)

strncpy会将数据复制到您指定的限制 - 但如果它在字符串结尾之前达到该限制,则会离开目标未终结。< / p>

换句话说,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] = '\0';
}

因为你已经将它标记为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] = '\0';
}

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

答案 1 :(得分:2)

反对使用strncpy的论点是它不保证你的字符串将被终止。

使用非固定长度数组时,在C中复制字符串的错误较少的方法是使用snprintf来保证字符串的空终止。

Blog Post评论*n*个功能。

  

这些函数允许您指定缓冲区的大小但是 - 这非常重要 - 它们不保证空终止。如果你要求这些函数写入比填充缓冲区更多的字符,那么它们将停止 - 从而避免缓冲区溢出 - 但它们不会使终止缓冲区。

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

答案 2 :(得分:0)

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

strncpy()的限制:

  1. 如果目标字符串已完全填充,则它不会在目标字符串上放置空终止符。并且,如果source长于num。
  2. ,则不会在目标末尾隐式附加空字符
  3. 如果num大于源字符串的长度,则使用空字符填充目标字符串,最多为num length。
  4. 与strcpy一样,它不是一个内存安全的操作。因为它在复制源之前没有在目标中检查足够的空间,所以它可能是缓冲区溢出的原因。

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

答案 3 :(得分:-1)

我们有2个版本的复制字符串从一个到另一个 1 GT;的strcpy 2 - ;函数strncpy 这两个版本用于固定和非固定长度数组。 strcpy在复制字符串时不检查目标字符串的上限,strncpy会检查它。当目标字符串到达​​此上限时,函数strncpy将返回错误代码,同时函数strcpy将在当前进程的内存中产生一些影响并立即终止进程。因此strncpy比strcpy更安全