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() 的局限性:
- 如果目标字符串已完全填充,则不会在目标字符串上放置空终止符。并且,如果源长于 num.
,则不会在目标末尾隐式附加空字符。
- 如果 num 大于源字符串的长度,目标字符串将用空字符填充到 num 长度。
和strcpy一样,它不是内存安全操作。因为它在复制源之前没有检查目标中是否有足够的 space,所以它是缓冲区溢出的潜在原因。
参考:Why should you use strncpy instead of strcpy?
我们有 2 个版本用于将字符串从一个版本复制到另一个版本
1> 结构化
2> 结构化
这两个版本用于固定和非固定长度数组。复制字符串时,strcpy 不检查目标字符串的上限,strncpy 会检查它。当目标字符串达到此上限时,函数 strncpy 将显示 return 错误代码,同时函数 strcpy 将对当前进程的内存产生一些影响并立即终止进程。这样 strncpy 比 strcpy
更安全
根据 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() 的局限性:
- 如果目标字符串已完全填充,则不会在目标字符串上放置空终止符。并且,如果源长于 num. ,则不会在目标末尾隐式附加空字符。
- 如果 num 大于源字符串的长度,目标字符串将用空字符填充到 num 长度。
和strcpy一样,它不是内存安全操作。因为它在复制源之前没有检查目标中是否有足够的 space,所以它是缓冲区溢出的潜在原因。
参考:Why should you use strncpy instead of strcpy?
我们有 2 个版本用于将字符串从一个版本复制到另一个版本 1> 结构化 2> 结构化 这两个版本用于固定和非固定长度数组。复制字符串时,strcpy 不检查目标字符串的上限,strncpy 会检查它。当目标字符串达到此上限时,函数 strncpy 将显示 return 错误代码,同时函数 strcpy 将对当前进程的内存产生一些影响并立即终止进程。这样 strncpy 比 strcpy
更安全