为什么 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结束后继续打印。
如果不插入0
,printf
的结果是未定义的。
您调用 未定义行为 试图打印 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;
这个问题让我大吃一惊...任何人都可以解决这个问题,因为我已经在这上面浪费了很多时间..;(
#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结束后继续打印。
如果不插入0
,printf
的结果是未定义的。
您调用 未定义行为 试图打印 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;