我可以指出你的男人网页,网站等,但最终重要的是C标准本身。作为标准运行时库的一部分,使用和行为在C99-§7.23.2.4定义为:
#include <string.h>
char *strncpy(char * restrict s1,
const char * restrict s2,
size_t n);
说明 的strncpy
功能拷贝不超过n个字符(即遵循一个字符空字符不会被复制)从s2指向的数组转到 s1指向的数组。如果在重叠对象之间进行复制,则行为不确定。 如果s2指向的数组的长度小于n个字符,则在s1指向的数组副本中会添加空字符,直到写入全部n个字符为止。
返回 strncpy
函数返回s1的值。
有显著隐含的信息在这里,最重要的是:strncpy()
将不以空字符终止您的目标字符串,如果源字符串长度(不包括其空字符终止)达到或超过指定的目标缓冲区长度)。
此外,虽然在标准中明确规定(见上文),它继续混淆了我很多的工程师怎么都没有意识到,strncpy()
尾填充空字符到指定的长度n
目标字符串缓冲区到达时源字符串长度为,比目标缓冲区大小小。这得出了以下不可避免的结论:
strncpy()
API将始终将n
字符写入目标缓冲区引用的地址。
在你的情况,因为目标缓冲区只有10字符宽,你写90个其他字符过去写存储器的定义高端,因此走进的未定义行为土地。
在这一点上,你必须问自己:“那么最新的使用?”有是一个可以说是最基本的用例。它允许你复制最多n
字符到目标缓冲区,并且知道你不会超过n
字符。期。不过说到底,你想有一个空值终止字符串,因此的正确用法是这样的:
char dst[ N ];
strncpy(dst, src, N-1);
dst[N-1] = 0;
其中N
是dst
缓冲区的硬长度字符,是大于,或相等到1
。需要注意的是dst
可能只是-AS-不失为一个动态分配的内存指针:
char *dst = malloc(N * sizeof(char));
strncpy(dst, src, N-1);
dst[N-1] = 0;
通过上述,您将总是必须在dst
一个空结尾的字符串。如果源字符串长度为小于指定的目标缓冲区长度,则strncpy()
将用空字符尾部填充缓冲区的其余部分,直到源字符复制+尾部填充空字符总数等于n
,并且最后的陈述是多余的。如果源字符串长度为等于或大于目标缓冲区长度,则strncpy()
将停止复制一次N-1
达到字符数,并且最终语句在缓冲区末尾设置空字符。这会导致原始源代码的“精简”前缀字符串,但最重要的是,它可以确保您不会超出目标缓冲区的边界,而后面的字符串API调用将扫描终结符。
上述技术的有用性总是值得商榷的。我是一个C++的人,所以std::string
拯救了我所有这种疯狂的快乐。但现实情况是这样的:有时候你会在乎src
是否在其整体到dst
中被复制;有时候你没有。有用性是很情况依赖。为了在UI中呈现字符串数据,这不会(可能)重要。对于复制要用于关键数据的字符串,部分前缀子字符串不会被接受。当警方向“约瑟夫约翰逊约翰”发出逮捕令时,当他的父亲(“约瑟夫约翰逊”)被囚禁入狱时,会有一些解释要做,因为权证发行软件的名字缓冲区只有15个字符。
所有这一切说,你分段故障归结为这样一句话:
strncpy(s1.from_str,src, 100); // length parameter is wrong.
产品召回大胆的声明,上面:“strncpy()
将永远写n
字符由目标缓冲区中引用的地址。”。这意味着上述代码将总是写入100个字符到目标缓冲区,在您的情况下只有10个字符宽,因此未定义的行为,并可能ker-boom。
通过执行纠正这种如果目标缓冲区是一个固定长度的字符数组以下:
strncpy(s1.from_str,src, sizeof(s1.from_str)/sizeof(s1.from_str[0])-1);
s1.from_str[ sizeof(s1.from_str)/sizeof(s1.from_str[0])-1 ] = 0;
参见如何做到这一点对于长度`Ñ字符的动态字符串的先前使用。
你认为它应该尝试做什么,它做什么是两个完全不同的东西。 –