我只是在玩弄strncpy。
我的程序看起来像这样
typedef struct
{
char from_str[10];
}test;
main ()
{
test s1;
memset(&s1,0,sizeof(test));
char src[10]="himansh";
char dest[10];
memset(dest,0,10);
src[3]='\0';
printf("src is %s and strlen is %d \n",
src,strlen(src));
fflush(stdout);
strncpy(s1.from_str,src,100);
printf("s1.from_str is %s , src is %s \n",
s1.from_str,src);
return 1;
}
在执行strncpy之前,我在"src“字符串中添加了一个"\0”字符,"src“字符串的长度变为3,目标数组的大小为10 .But。
这意味着我的源字符串是NULL终止的。现在,strncpy和任何字符串函数一样,应该只复制3个字节,即使我提供的字节数大于3(在本例中是100)。它确实做到了这一点,但我也得到了一个分段错误。
我的结果如下所示
src is him and strlen is 3
s1.from_str is him , src is him
Segmentation fault (core dumped)
为什么这个分段故障会发生在这里。
有没有人能帮我。
发布于 2012-12-28 16:59:42
我可以向您介绍手册页、网站等,但最终重要的是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
。这得出了以下不可避免的结论:
API将始终将 n
字符写入目标缓冲区引用的地址。
在您的例子中,因为目标缓冲区只有10个字符宽,所以在可写内存的已定义端之外额外写入了90个字符,从而进入了未定义行为的领域。
在这一点上,您必须问自己“那么有什么用呢?”有一个有争议的基本用例。它允许您将最多n
字符复制到目标缓冲区,并可预测您不会溢出过去的n
字符。句号。不过,最终您需要一个以null结尾的字符串,因此正确的用法如下:
char dst[ N ];
strncpy(dst, src, N-1);
dst[N-1] = 0;
其中N
是dst
缓冲区的硬长度(以字符为单位),大于或等于1
。注意,dst
也可以是一个动态分配的内存指针:
char *dst = malloc( N * sizeof(char) );
strncpy(dst, src, N-1);
dst[N-1] = 0;
使用上面的代码,您将在dst
中始终有一个以null结尾的字符串。如果源字符串长度小于指定的目标缓冲区长度,strncpy()
会用空字符填充缓冲区的其余部分,直到源字符复制+尾部填充的空字符总数等于n
,最后的语句是冗余的。如果源字符串长度等于或大于目标缓冲区长度,则一旦达到N-1
字符,strncpy()
将停止复制,并且最后一条语句在缓冲区的末尾设置一个空字符。这将导致原始源的“缩减”前缀字符串,但最重要的是,它确保您不会使用稍后扫描终止符的string-API调用超出目标缓冲区的边界。
上述技术的有效性总是有争议的。我是一个C++的家伙,所以std::string
从所有这些疯狂中拯救了我的快乐自我。但现实是这样的:有时你会关心src
是否被完整地复制到dst
中;有时你不会。其有用性取决于,非常依赖于的情况。对于在UI中显示字符串数据,这(很可能)无关紧要。对于复制用于关键数据的字符串,部分前缀-子字符串是不能接受的。当警方向“小约瑟夫·约翰逊”发出通缉令时,当他的父亲(“约瑟夫·约翰逊”)被关进监狱时,将会有一些解释,因为签发令状软件的名称缓冲区只有15个字符。
所有这些,你的分段错误都可以归结为下面的语句:
strncpy(s1.from_str,src, 100); // length parameter is wrong.
回想一下上面的粗体语句:"**strncpy()
** n
将始终将字符写入目标缓冲区引用的地址。“.这意味着上面的代码将总是写100个字符到目标缓冲区,在你的例子中只有10个字符宽,因此未定义的行为和可能的-。
如果目标缓冲区是固定长度的字符数组,请执行以下操作来纠正此问题:
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;
有关如何对长度为`N个字符的动态字符串执行此操作,请参阅先前的用法。
发布于 2012-12-28 14:16:48
来自http://www.cplusplus.com/reference/cstring/strncpy/
源char * strncpy ( char *
,const char * source,size_t num );
Copy characters string将源的前num个字符复制到目标。如果在复制num个字符之前找到源C字符串的末尾(以空字符表示),则使用零填充目标,直到总共写入了num个字符。
因此,尽管源字符串长度小于目标缓冲区大小,但由于strncpy的传递行为,它会尝试覆盖超出目标缓冲区大小的其余字符,从而导致分段错误
大小应该等于目标缓冲区中允许的最大大小,而不是复制超过100个字符,因此,您可以这样写
strncpy(s1.from_str,src,sizeof(s1.from_str)/sizeof(s1.from_str[0]) - 1); Actual size -1 to accomodate the null terminator
或者更好地编写一个_countof
宏
#define _countof(s) (sizeof(s)/sizeof(s[0]))
................
strncpy(s1.from_str,src,_countof(s1.from_str) - 1);
发布于 2012-12-28 14:15:28
请参阅:http://www.manpagez.com/man/3/strncpy/
stpncpy()和strncpy()函数将最多n个字符从s2复制到s1中。如果s2的长度小于n个字符,则s1的其余部分将填充`\0‘个字符。否则,不会终止s1。
其余部分已填满...
所以:
strncpy( s1.from_str, src, 10 );
https://stackoverflow.com/questions/14065391
复制相似问题