为什么应该使用strncpy而不是strcpy?

109

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

我发现了这个示例

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 );

这段代码产生了以下输出:

目标初始值=`abcdefg`
执行strcpy后,目标变为`123456789`
目标1初始值=`abcdefg` 执行strncpy后,目标1变为`12345fg`

这让我想知道为什么会有人想要这种效果。看起来会很混乱。这个程序让我觉得你基本上可以用Tom Bro763覆盖某人的姓名(例如Tom Brokaw)。

使用strncpy()相比于使用strcpy()有哪些优势?


97
我认为你想问的是“为什么会有人使用strcpy而不是strncpy?” - Sam Harwell
9
我对“strncpy()”的不满这篇文章探讨了C语言函数“strncpy()”的问题。很多人认为“strncpy()”比“strcpy()”更安全,但作者指出了它的一些缺陷。作者认为,“strncpy()”虽然可以限制复制的字符数量,但它并没有确保目标字符串以空字符结尾。如果源字符串长度超过目标字符串的长度,则没有空字符,这可能导致访问未定义的内存并引起程序故障。此外,“strncpy()”在处理不足长度的源字符串时会用空字符来填充目标字符串,这会使目标字符串变得比实际需要更长。这可能会浪费内存并且给程序带来潜在的风险。最后,作者提到了其他替代方案,例如使用更安全的函数“strlcpy()”或手动添加空字符以确保目标字符串的正确性。总之,作者建议开发人员在使用“strncpy()”时要小心谨慎,考虑它的潜在风险并寻找更好的解决方案。 - Keith Thompson
1
@KeithThompson:从设计的角度来看,我认为strncatstrncpy更愚蠢;我们多少次会知道一个未知长度字符串后面的缓冲区还剩多少空间?如果目标字符串的长度是已知的,应该找到源字符串的长度(如果未知),将该值夹在可用的缓冲区空间内,然后使用memcpy复制适合的部分,并手动存储零。如果目标字符串的长度未知,则通常需要找到其长度以了解超出多少空间可用,在这种情况下仍适用上述方法。 - supercat
1
我很惊讶看到@SamHarwell的评论在这里得到了这么多的赞同; 它似乎完全忽略了OP完全合理的问题的要点,即strncpy具有超出您所期望的奇怪行为,这是“更安全的strcpy版本”。 - xdavidliu
11个回答

-8

strncpy是strcpy的更安全版本,事实上你永远不应该使用strcpy,因为它存在潜在的缓冲区溢出漏洞,这会使你的系统容易受到各种攻击。


6
请参阅http://www.lysator.liu.se/c/rat/d11.html:strncpy函数strncpy最初被引入到C库中,用于处理结构体中的固定长度名称字段,例如目录条目。这些字段的使用方式与字符串不同:对于最大长度字段,尾随空值是不必要的,并且将尾随字节设置为null可以确保有效地逐个字段进行比较。strncpy并非起源于“有界strcpy”,委员会更倾向于承认现有做法,而不是修改该函数以更好地适应这种用途。 - Sinan Ünür

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接