c strncpy null 是否终止

c strncpy null terminated or not

我正在阅读 this 文档,它说:

char *strncpy(char *destination, const char *source, size_t num);

Copy characters from string Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.

No null-character is implicitly appended at the end of destination if source is longer than num. Thus, in this case, destination shall not be considered a null terminated C string (reading it as such would overflow).

destination and source shall not overlap (see memmove for a safer alternative when overlapping).

但我对这个说法感到困惑:

in this case, destination shall not be considered a null terminated C string (reading it as such would overflow)

因为如果num > strlen(source),它会在末尾填充'[=26=]''[=26=]'实际上是一个字符串中的空(终止)字符,为什么它不应该被认为是一个以 null 结尾的 C 字符串?

我写了下面的代码来验证:

  char from[] = { 'h', 'e', 'l', 'l', 'o', '[=11=]' };
  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

说的是 strlen(source) > num 的情况。它只会复制 num 个字符,其中 none 个是 NUL,并且不会添加 NUL。

strncpy(dst, src, len) 仅在前 len 字节内的 src 中存在空终止符时才向 dst 添加空终止符。您的代码似乎可以工作,因为数组 to[] 之后可能有也可能没有空字符。更好的测试是:

char source[] = "source";
char dest[] = "destination";
strncpy(dest, source, 6);
printf("%s\n", dest);

结果应该是:

sourceation

如果您改写 strncpy(dest, source, 7),则输出只是单词 source

strncpy() 的语义,即使在上面的 C++ 参考中进行了精确解释,也被广泛误解。此函数的行为违反直觉且容易出错。

为了避免在使用它或进一步开发过程中出现问题,当维护者会误读代码并添加更多微妙的错误时,有一个简单的解决方案:永远不要使用这个功能.

您可以在 this article by Bruce Dawson 中阅读有关此内容的更多详细信息。

回答你的问题:如果源字符串长于作为第三个参数传递的大小(通常对应于目标缓冲区的大小),该函数会将 size 个字符复制到目标并且不会有空字节存在于其中。然后调用 strlen(destination); 将调用未定义的行为,因为它将尝试读取超出数组末尾的内容,直到找到空终止符。这种特定行为是 strncpy 如此容易出错的原因。