根据此StackOverflow注释,strncpy
不应与非固定长度数组一起使用。
strncpy
永远不应该使用,除非您在处理结构/二进制文件中的固定宽度(不一定是终止的字符串字段)。–R..一月11'12在16:22
我知道,如果您为字符串动态分配内存,这是多余的,但是否有理由使用strncpy
而不是strcpy
strncpy
会将数据复制到您指定的限制,但如果它在字符串结束前达到该限制,则会使目标未终止。
换句话说,strncpy
有两种可能性。一种是,您得到的行为与strcpy
无论如何都会产生的行为完全一样(除了速度较慢,因为它用NUL填充了目标缓冲区的剩余部分,而实际上您从来都不想要或关心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] = ' ';
}
由于您已经将其标记为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] = ' ';
}
只有当目标是实际数组(而不是指针)时,这才有效,但在这种情况下,它会让编译器推断数组的大小,而不需要用户显式传递。这通常会使代码更快一点(减少函数调用的开销),更难搞砸和传递错误的大小。
反对使用strncpy
的论点是,它不能保证字符串以null结尾。
当使用非固定长度数组时,在C中复制字符串的不太容易出错的方法是使用snprintf
,它可以确保字符串的null终止。
一篇很好的博客文章,评论*n*
的功能。
这些函数允许您指定缓冲区的大小,但这一点非常重要,它们不能保证null终止。如果您要求这些函数写入比填充缓冲区更多的字符,那么它们将停止,从而避免缓冲区溢出,但它们不会null终止缓冲区。
这意味着在不处理固定数组时使用strncpy
和其他此类函数会带来非空终止字符串的不必要风险,这些字符串可能会成为代码中的定时炸弹。
char*strncpy(char*目的地,const char*源,size_t num)
strncpy()的限制:
- 如果目标字符串已完全填充,则不会在其上放置null终止符。并且,如果source比num.长,则不会在destination的末尾隐式附加null字符
- 如果num大于源字符串的长度,则目标字符串将填充长度不超过num的空字符
与strcpy一样,它不是内存安全操作。因为它在复制源之前并没有检查目标中是否有足够的空间,所以这是导致缓冲区溢出的潜在原因。
参考:为什么要使用strncpy而不是strcpy?
我们有两个版本可以将字符串从一个复制到另一个1> strcpy2> strncpy这两个版本用于固定长度数组和非固定长度数组。strcpy在复制字符串时不检查目标字符串的上限,strncpy会检查它。当目标字符串达到这个上限时,函数strncpy将返回错误代码,同时函数strcpy会在当前进程的内存中造成一些影响,并立即终止进程。因此strncpy比strcpy 更安全