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