编辑:我添加了示例的来源。

我碰到 这个示例:

char source[MAX] = "123456789";
char source1[MAX] = "123456789";
char destination[MAX] = "abcdefg";
char destination1[MAX] = "abcdefg";
char *return_string;
int index = 5;

/* This is how strcpy works */
printf("destination is originally = '%s'\n", destination);
return_string = strcpy(destination, source);
printf("after strcpy, dest becomes '%s'\n\n", destination);

/* This is how strncpy works */
printf( "destination1 is originally = '%s'\n", destination1 );
return_string = strncpy( destination1, source1, index );
printf( "After strncpy, destination1 becomes '%s'\n", destination1 );

产生了此输出:

destination is originally = 'abcdefg'
After strcpy, destination becomes '123456789'

destination1 is originally = 'abcdefg'
After strncpy, destination1 becomes '12345fg'

这让我想知道为什么有人会想要这种效果。看起来这会令人困惑。这个程序使我认为您基本上可以与汤姆·兄弟(Tom Bro763)一起复制某人的名字(例如汤姆·布罗科(Tom Brokaw))。

使用的优点是什么 strncpy() 超过 strcpy()?

有帮助吗?

解决方案

strncpy 打击缓冲区溢出,要求您在其中添加长度。 strcpy 取决于尾声 \0, ,这可能并非总是发生。

其次,为什么您选择在7个字符字符串上仅复制5个字符的原因超出了我,但它会产生预期的行为。它只是在第一个复制 n 角色,哪里 n 是第三个论点。

n 功能全部用作防御性编码,以防止缓冲区溢出。请使用它们代替旧功能,例如 strcpy.

其他提示

strncpy() 函数的设计有一个非常特殊的问题:以原始Unix目录条目的方式操纵字符串。这些使用了固定尺寸的数组,仅当文件名比阵列短时才使用NUL末端。

这就是两个怪异的背后 strncpy():

  • 如果完全填充了目标,它不会在目的地上放置nul末端。和
  • 它总是完全填充目的地,如有必要。

为了“更安全 strcpy()”,最好使用 strncat() 像这样:

if (dest_size > 0)
{
    dest[0] = '\0';
    strncat(dest, source, dest_size - 1);
}

这将始终将结果终止,并且不会复制超过必要的。

虽然我知道背后的意图 strncpy, ,这并不是一个好功能。避免两者。 雷蒙德·陈(Raymond Chen)解释了.

就个人而言,我的结论只是避免 strncpy 以及所有的朋友,如果您要处理无效的终止字符串。尽管名称为“ str”,但这些功能并未产生无效的终止字符串。他们将无效的字符串转换为原始角色缓冲区。在预期的,因为第二个缓冲区是错误的,因此使用它们的位置。如果源太长,您不仅无法获得正确的零终止,而且如果源很短,您会不会获得不必要的空填充。

也可以看看 为什么Strncpy不安全?

strncpy并不比Strcpy更安全,它只是将一种类型的错误与另一种错误交易。在C中,当处理C字符串时,您需要知道缓冲区的大小,因此无法周围。 strncpy对于他人提到的目录事物是有道理的,但是否则,您绝不应该使用它:

  • 如果您知道字符串和缓冲区的长度,为什么要使用strncpy?它充其量只是浪费计算能力(添加无用的0)
  • 如果您不知道长度,那么您就有静静地截断弦的风险,这并不比缓冲区溢出要好得多

您正在寻找的是功能 strlcpy() 确实终止了带有0的字符串并初始化缓冲区。它还能够检测到溢出。唯一的问题,它不是(实际上)便携式,并且仅存在于某些系统(BSD,Solaris)上。此功能的问题在于,它可以打开另一罐蠕虫,如上所述http://en.wikipedia.org/wiki/strlcpy

我个人的看法是,它比 strncpy()strcpy(). 。它具有更好的性能,是一个很好的伴侣 snprintf(). 。对于没有它的平台,它相对容易实现。 (对于应用程序的开发阶段,我替代了这两个功能(snprintf()strlcpy())带有陷阱版本,该版本在缓冲区溢出或截断方面残酷地中止程序。这样可以迅速抓住最糟糕的罪犯。特别是如果您在其他人的代码库上工作。

编辑: strlcpy() 可以轻松实现:

size_t strlcpy(char *dst, const char *src, size_t dstsize)
{
  size_t len = strlen(src);
  if(dstsize) {
    size_t bl = (len < dstsize-1 ? len : dstsize-1);
    ((char*)memcpy(dst, src, bl))[bl] = 0;
  }
  return len;
}

strncpy() 功能是更安全的:您必须传递目标缓冲区可以接受的最大长度。否则可能会遇到源字符串正确0终止,在这种情况下 strcpy() 功能可以将更多字符写入目标,损坏目标缓冲区后的内存中的任何内容。这是许多漏洞中使用的缓冲区超越问题

也适用于POSIX API函数 read() 不会将终止0放在缓冲区中,而是返回读取的字节数,您将手动放置0,或使用它复制 strncpy().

在您的示例代码中 index 实际上不是索引,而是 count - 告诉多少个字符 最多 从源到目的地复制。如果第一个源源中没有null字节,则将放置在目的地中的字符串将不会被终止

对于源的大小,strncpy填充了目的地的“ 0”,尽管目的地的大小较小。

manpage:

如果SRC的长度小于N,则用无效字节将DEST的其余部分垫垫。

不仅剩余的……还直到达到n个字符。因此,您会溢出...(请参阅《人页面实现》)

这可以在许多其他情况下使用,其中您只需要将原始字符串的一部分复制到目的地。使用strncpy(),您可以复制原始字符串的有限部分,而不是strcpy()。我看到您提出的代码来自 publib.boulder.ibm.com.

这取决于我们的要求。适用于Windows用户

每当我们不想复制整个字符串或只需复制n个字符数时,我们就会使用strncpy。但是strcpy复制了整个字符串,包括终止空字符。

这些链接将帮助您更多地了解Strcpy和Strncpy以及我们可以使用的地方。

关于strcpy

关于strncpy

strncpy是strcpy的更安全的版本,实际上您永远不应该使用strcpy,因为它的潜在缓冲区溢出脆弱性使您系统容易受到各种攻击

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top