我知道strncpy
是一个比strcpy
更安全的here。
但是,当我想从src
复制到dst
并且dst
不是一个干净的缓冲区时,我会得到不需要的结果,这可以通过strcpy
来避免:
char *p = "123";
char a[10] = "aaaaaa";
strncpy(a,p,strlen(p));
printf("%s\n", a); // 123aaa
strcpy(a,p);
printf("%s\n", a); // 123 <- desired output, as the trailing a's are garbage
在我的实际情况中,我知道strlen(src) < sizeof(dst)
(至少,如果不是这样,程序会很快崩溃),所以我可以安全地strcpy
。
但是,如果我应该使用strncpy
,那么我必须在dst[strlen(src)] = '\0'
之后添加以避免垃圾(或者更好的是,事先启动缓冲区吗?)?
strncpy
的第三个参数用于表示目标缓冲区的大小。当它填满时,它不会通过设计添加空终止字符。
如果你有足够的空间用于终结者并且你坚持使用strncpy
,那么只需通过strlen(p) + 1
,这样就不会认为它耗尽了目标缓冲区。
像许多人已经注意到的那样。这种strncpy
的使用击败了目的,并且实际上并不比简单地调用strcpy
更好。 strncpy
的唯一实际用途是,如果你想要就地覆盖一部分字符串(这是你偶然发现的用例)。虽然这也是值得怀疑的......
如何正确使用strncpy?
当代码需要将字符串复制到目标并且容忍结果不是空字符终止或完全复制时,请使用sizeof destination
作为size参数:
char a[10];
// strncpy(a,p,strlen(p));
strncpy(a, p, sizeof a);
// printf("%s\n", a);
printf("%.*s\n", (int) sizeof a, a);
当代码想要复制字符串并通过strncpy()
检测不足的内存问题或需要空字符'\0'
填充时,也使用sizeof destination
。
char a[10];
strncpy(a, p, sizeof a);
if (a[sizeof a - 1] != '\0') {
// insufficient memory
// Maybe set last last character to the null character
a[sizeof a - 1] == '\0';
// or other more robust handling
return ERROR_INSUFFICIENT_MEMORY;
}
否则不要使用strncpy()
当不需要空字符strncpy()
填充时,有更有效的方法来检测不足内存而不是通过'\0'
。 strncpy()
零填充未复制缓冲区的其余部分(如果有)。以下消耗大量时间零填充只是为了提供不足检查。
char a[1000];
strncpy(a, "abc", sizeof a);
if (a[sizeof a - 1] != '\0') {
....
更好的替代品采用strlen(), strlcpy(), memcpy()
。 @Deduplicator。
另见strncpy or strlcpy in my case。
对于标准的C lib单行代码,代码可以使用snprintf()
和一行错误检测。一个好的编译器可以分析snprintf(a, sizeof a, "%s", p)
并发出有效的代码。
// Copy with no overflow.
// 'a' is always null character terminated.
int len = snprintf(a, sizeof a, "%s", p);
if (len < 0 || len >= sizeof a) Report_truncated_copy();
strncpy()
实际上不是一个字符串函数;相反,它处理哪些零填充的非零字符序列,它们一起具有已知的固定长度。例如,它是填充数据结构的正确工具,这些数据结构随后被发送到其他程序,外部或持久化,以避免数据泄漏。
试图在非常专业的利基之外使用它会导致可怕的扭曲和低效的代码。
还有更合适的方法,比如strlcpy()
和/或手动使用strlen()
和memcpy()
。