我正在学习c中的字符串。我使用code :: blocks作为编译器,即使它不仅仅用于c。因此,下面代码的问题是string2的输出是存储的5个字符加上string1的输出。我会告诉你:
#include <stdio.h>
#include <string.h> /* make strncpy() available */
int main()
{
char string1[]= "To be or not to be?";
char string2[6];
/* copy first 5 characters in string1 to string2 */
strncpy (string2, string1, 5);
printf("1st string: %s\n", string1);
printf("2nd string: %s\n", string2);
return 0;
}
输出是:
1st string contains: To be or not to be?
2nd string contains: To be To be or not to be?
如果你问我,那就超过了5个字符......
答案 0 :(得分:10)
来自strncpy
手册页:
没有空字符隐式附加到目标的末尾,因此如果源中的C字符串的长度小于num,则目标将仅以空值终止。
由于原始字符串的长度大于5,因此不会添加NULL。
正如其他人所指出的那样,为它增加一些安全性:
strncpy (string2, string1, sizeof(string2));
string2[sizeof(string2)-1] = '\0';
请注意,如果string2
是通过malloc()
:
char * string2 = malloc(123); //sizeof(string2) == sizeof(void *) and not 123
上面的代码会失败。
为了完整起见,这里是代码:http://ideone.com/eP4vd
答案 1 :(得分:3)
您没有使用'\ 0'终止string2,因此printf溢出。尝试做:
memset(string2,0,6);
在使用string2之前。 或者,因为你知道你正在复制5个字符,在strncpy之后:
string2[5] ='\0';
所以你正确地正确终止了字符串。
请注意你应该在你复制的字符数之后加上'\ 0',否则你甚至会在字符串的中间看到垃圾。
答案 2 :(得分:1)
基本上两个字符串都在内存中彼此相邻的堆栈上,并且在string2之后没有空终止符,因此当它打印时,它会从string2
+随机的一个字节值打印“待定”({在点击空字节之前{1}})+ string2[5]
(“成为或不成为”)。
如果随机的一个字节值为0,它将停止。你会得到你期望的印刷品。
答案 3 :(得分:0)
您的string2
不包含\0
,因此此字符串不会终止。当你打印它时,它超出了它的界限并打印它在那里找到的任何内容,直到它找到\0
。
在每个strncpy
之后,如果您想要正确终止字符串,则必须手动插入\0
。
答案 4 :(得分:0)
strncpy有局限性,见上文。 看看像sprintf一样的
sprintf( string2, "%.*s", sizeof(string2)-1, string1 );
答案 5 :(得分:0)
strncpy()
,尽管名称不同,但它不仅仅是strcpy()
更安全的边界指定版本。这是一个模糊的函数,具有模糊的语义,我认为它不应该被包含在C标准库中。
strncat()
是更安全的边界指定版strcat()
。
这是一个解决方案:
char string1[]= "To be or not to be?";
char string2[6];
string2[0] = '\0';
strncat (string2, string1, 5);