为什么 strncpy() 不遵守给定的 size_t n,它在 temp2 中是 10?

Why strncpy() is not respecting the given size_t n which is 10 in temp2?

这个问题让我大吃一惊...任何人都可以解决这个问题,因为我已经在这上面浪费了很多时间..;(

#include <stdio.h>
#include <string.h>
int main(){

  char string[] = "Iam pretty much big string.";
  char temp1[50];
  char temp2[10];

  // strcpy() and strncpy()
   strcpy(temp1, string);
   printf("%s\n", temp1);

  strncpy(temp2, temp1, 10);
  printf("%s\n", temp2);
  return 0;
}

结果

Iam pretty much big string.
Iam prettyIam pretty much big string.

预期结果:

Iam pretty much big string.
Iam pretty

temp2的地址就在temp1的地址之前,因为你没有复制最后的0,printf会在temp2结束后继续打印。

如果不插入0printf的结果是未定义的。

您调用 未定义行为 试图打印 temp2 因为 temp2 不是 nul-terminated。来自 man strncpy:

"Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated." (emphasis in original)

另请参阅 C11 Standard - 7.24.2.4 The strncpy function(特别是 脚注: 308)

所以 temp2 不是以 nul 结尾的。

来自 strncpy() 的联机帮助页:

Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.

要么您的输入比提供的长度短,要么您自己添加终止空字节,要么它不会存在。 printf() 期望字符串正确地以 null 终止,因此会超出您分配的缓冲区。

这只能表明许多标准函数的 n 变体绝不安全。您必须阅读它们各自的手册页,并专门查看当提供的长度不够时它们会做什么。

在 Stack Overflow https://whosebug.com/tags/strncpy/info 上引用了适当的 [strncpy] 标签,这可能有助于您理解到底发生了什么:


不建议将此函数用于任何目的,无论是在 C 还是 C++ 中。 It was never intended to be a "safe version of strcpy" 但经常被滥用于此类目的。它实际上被认为比 strcpy 危险得多,因为 strncpy 的空终止机制不直观,因此经常被误解。这是因为 ISO 9899:2011 7.24.2.4:

指定了以下行为
char *strncpy(char * restrict s1, 
     const char * restrict s2, 
     size_t n);

/--/

3 If the array pointed to by s2 is a string that is shorter than n characters, null characters are appended to the copy in the array pointed to by s1, until n characters in all have been written.

一个非常常见的错误是传递一个 s2 ,它与 n 参数的字符数完全一样,在这种情况下 s1 不会以 null 终止。即:strncpy(dst, src, strlen(src));

/* MCVE of incorrect use of strncpy */
#include <string.h>
#include <stdio.h>

int main (void)
{
  const char* STR = "hello";
  char buf[] = "halt and catch fire";
  strncpy(buf, STR, strlen(STR));
  puts(buf); // prints "helloand catch fire"
  return 0;
}

C 中的推荐做法是提前检查缓冲区大小,然后使用 strcpy(),或者 memcpy()。 C++ 中的推荐做法是使用 std::string 代替。

strncpy 函数 尊重您给它的 10 字节限制。

它将前 10 个字节从 string 复制到 temp2。这10个字节中的None是空字节,而temp2的大小是10,所以temp2中没有空字节。当您随后将 temp2 传递给 printf 时,它会读取调用 undefined behavior.

的数组末尾

您需要将给定 strncpy 的大小设置为数组大小 - 1,然后手动将空字节添加到末尾。

strncpy(temp2, temp1, sizeof(temp2)-1);
temp2[sizeof(temp2)-1] = 0;