我正在阅读this文件,它说:
char *strncpy(char *destination, const char *source, size_t num);
从字符串中复制字符 将
num
的前source
个字符复制到destination
。如果在复制source
个字符之前找到num
C字符串的结尾(由空字符表示),则{0}填充destination
,直到总共num
1}}字符已写入其中。如果source超过
num
,则不会在目标末尾隐式附加空字符。因此,在这种情况下,destination
不应被视为空终止的C字符串(因此读取它会溢出)。
destination
和source
不得重叠(重叠时请参阅memmove
了解更安全的替代方案。)
但我对此声明感到困惑:
在这种情况下,destination不应被视为空终止的C字符串(读取它会溢出)
因为如果num > strlen(source)
在最后填充'\0'
,'\0'
实际上是字符串中的空(终止)字符,为什么它不应被视为空 - 终止了C字符串?
我在下面写了一些代码来验证:
char from[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
char to[1024];
for (int i = 0; i < 1024; i++) {
to[i] = 'e';
}
strncpy(to, from, 1024);
printf("from %s\n", from);
下面的输出效果很好:
from hello
to hello
答案 0 :(得分:6)
正在谈论strlen(source)
&gt;时的情况。 num
。它只会复制num
个字符,其中没有一个是NUL,也不会添加NUL。
答案 1 :(得分:5)
strncpy(dst, src, len)
字节中的dst
内存在空终止符,则 src
仅向len
添加空终止符。您的代码似乎可以工作,因为在数组to[]
之后可能有也可能没有空字符。更好的测试是:
char source[] = "source";
char dest[] = "destination";
strncpy(dest, source, 6);
printf("%s\n", dest);
结果应为:
sourceation
如果您改为编写strncpy(dest, source, 7)
,则输出只是单词source
。
答案 2 :(得分:3)
strncpy()
的语义,即使在上面的C ++参考文献中进行了精确解释,也被广泛误解。这个函数的行为是违反直觉的,容易出错。
为了避免在使用它或进一步开发过程中出现问题,当维护者误读代码并添加更多的漏洞时,有一个简单的解决方案:从未使用过这个功能。
您可以在this article by Bruce Dawson中阅读有关此内容的更多详情。
回答你的问题:如果源字符串长于作为第三个参数传递的大小(通常对应于目标缓冲区的大小),则该函数会将大小字符复制到目标,并且不会出现空字节在这些当中。然后调用strlen(destination);
将调用未定义的行为,因为它将尝试读取超出数组末尾的内容,直到找到空终止符。这种特定行为使strncpy
容易出错。