我知道strncpy
是here所说的strcpy
的安全版本。
但是,当我想从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'
之后添加以避免垃圾(或者可能更好,预先初始化缓冲区?)?
答案 0 :(得分:10)
strncpy
的第三个参数旨在表示目标缓冲区的大小。而且当它填满时,它不会按设计添加空终止符。
如果您有足够的空间容纳终止符,并且坚持使用strncpy
,则只需传递strlen(p) + 1
,这样就不会认为终止符耗尽了目标缓冲区。
就像现在已经注意到的许多。 strncpy
的这种用法无法达到目的,并且实际上不比简单调用strcpy
好。 strncpy
的唯一实际用法是,如果您想就地覆盖字符串的一部分(这是您偶然发现的用例)。虽然这也值得怀疑...
答案 1 :(得分:3)
如何正确使用strncpy?
当代码需要将字符串复制到目标位置并且容忍结果不是空字符终止或完全复制时,请对大小参数使用sizeof destination
:
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();
答案 2 :(得分:1)
strncpy()
实际上不是字符串函数;相反,它处理哪些填充零的非零字符序列,这些序列一起具有已知的固定长度。例如,它是填写数据结构的正确工具,然后将其发送到其他程序,发送到外部或持久保存以避免数据泄漏。
尝试在非常专业的领域之外使用它会导致可怕的扭曲和低效的代码。
有更多合适的方法可以解决此问题,例如strlcpy()
和/或手动使用strlen()
和memcpy()
。