【问题标题】:c strncpy null terminated or not [duplicate]c strncpy null终止与否[重复]
【发布时间】:2016-12-08 17:20:10
【问题描述】:

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

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

从字符串中复制字符 将source 的第一个num 字符复制到destination。如果在复制num 字符之前找到source C 字符串的结尾(由空字符表示),则用零填充destination,直到总共写入num 字符它。

如果源长于num,则不会在目标末尾隐式附加空字符。因此,在这种情况下,destination 不应被视为以 null 结尾的 C 字符串(这样读取它会溢出)。

destinationsource 不得重叠(重叠时请参阅memmove 以获得更安全的替代方案)。

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

在这种情况下,目的地不应被视为以空结尾的 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

【问题讨论】:

  • strncpy:别用就行了。
  • 缺少'\0'strlen(source) &gt; num,所以我认为您只是有一个简单的误解 - 请尝试使用strncpy(to, from, 2);

标签: c strncpy


【解决方案1】:

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

【讨论】:

  • ...并确保您确实获得 NUL 终止符,请使用 strlcpy 而不是 strncpy
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

    您可以在this article by Bruce Dawson 中阅读更多详细信息。

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

    【讨论】:

    • @EvilTeach:我更新了答案。阻止新手使用这个容易出错的功能很重要。我见过很多滥用的例子,即使是经验丰富的程序员……它充当了一个普遍的错误吸引器。
    • 这是现在最好的答案。遗憾的是,从不使用此功能不能在红色和黑色之间闪烁。
    • 我会将 strtok、atoi、atof 和整个 scanf 系列添加到要避免的函数列表中。
    • @EvilTeach:我同意strtokscanfatoiatof 不提供错误检查,但问题要少得多。 feof() 在列表中的排名也很高,sprintf() 应该替换为 snprintf()char 默认应该是无符号的,强制 2s 补码,以及 8/16/32/和 64 位整数类型, IEEE 浮点...这将使 C 变得简单得多。
    • @EvilTeach: feof()while (!feof(fp)) 中几乎被系统地滥用。默认签名的char 与返回unsigned char 类型加上EOF 的值的getc() 不一致,strcmp() 将字符串作为unsigned char 的数组和来自&lt;ctype.h&gt; 的函数进行比较,为负数@987654342 调用未定义的行为@值。
    猜你喜欢
    • 1970-01-01
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-30
    • 2019-07-09
    • 2017-05-29
    • 2021-09-28
    相关资源
    最近更新 更多