如何正确使用strncpy?

问题描述 投票:2回答:3

我知道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'之后添加以避免垃圾(或者更好的是,事先启动缓冲区吗?)?

c strcpy strncpy
3个回答
10
投票

strncpy的第三个参数用于表示目标缓冲区的大小。当它填满时,它不会通过设计添加空终止字符。

如果你有足够的空间用于终结者并且你坚持使用strncpy,那么只需通过strlen(p) + 1,这样就不会认为它耗尽了目标缓冲区。

像许多人已经注意到的那样。这种strncpy的使用击败了目的,并且实际上并不比简单地调用strcpy更好。 strncpy的唯一实际用途是,如果你想要就地覆盖一部分字符串(这是你偶然发现的用例)。虽然这也是值得怀疑的......


3
投票

如何正确使用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();

1
投票

strncpy()实际上不是一个字符串函数;相反,它处理哪些零填充的非零字符序列,它们一起具有已知的固定长度。例如,它是填充数据结构的正确工具,这些数据结构随后被发送到其他程序,外部或持久化,以避免数据泄漏。

试图在非常专业的利基之外使用它会导致可怕的扭曲和低效的代码。

还有更合适的方法,比如strlcpy()和/或手动使用strlen()memcpy()

© www.soinside.com 2019 - 2024. All rights reserved.