c strncpy null是否终止

c strncpy null terminated or not

本问题已经有最佳答案,请猛点这里访问。

我正在阅读这份文件,上面写着:

1
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),它将以'\0'结尾,因此'\0'实际上是字符串中的空(终止)字符,为什么不将其视为以空终止的C字符串?

我已编写以下代码进行验证:

1
2
3
4
5
6
7
8
  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
"
, from);

它在以下输出中正常工作:

1
2
from hello
to hello


谈论的是strlen(source)> num的情况。它只会复制num个字符,都不是NUL,也不会添加NUL。


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

1
2
3
4
5
char source[] ="source";
char dest[] ="destination";
strncpy(dest, source, 6);
printf("%s
"
, dest);

结果应为:

1
sourceation

如果改为写strncpy(dest, source, 7),则输出仅为单词source


strncpy()的语义,即使在上面的C ++参考文献中进行了精确解释时,也被普遍误解了。此功能的行为是违反直觉的,并且容易出错。

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

您可以在Bruce Dawson的这篇文章中阅读有关此内容的更多详细信息。

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