导致分段错误的strncpy
我只是在胡闹 我的程序是这样的导致分段错误的strncpy,c,segmentation-fault,strncpy,C,Segmentation Fault,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
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。但在strncpy中,我将要复制的字节数设置为100
这意味着我的源字符串以NULL结尾。现在,strncpy和任何字符串函数一样,应该尝试只复制3个字节,即使我提供的字节数超过3(在本例中为100)。确实如此,但我也有一个分割错误
我的结果如下所示
src is him and strlen is 3
s1.from_str is him , src is him
Segmentation fault (core dumped)
为什么分割错误会发生在这里
有人能帮我吗。请看:
stpncpy()和strncpy()函数最多从s2复制n个字符
进入s1。如果s2的长度小于n个字符,则s1的剩余部分为
用“\0”字符填充。否则,s1不终止
剩下的就填了
因此:
从
char*strncpy(char*destination,const char*source,size\u t num
);
复制字符串中的字符复制源的第一个num字符
去目的地。如果源C字符串的结尾(这是有信号的
在复制num个字符之前找到,
目标用零填充,直到总共包含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
或者最好编写一个\u countof
宏
#define _countof(s) (sizeof(s)/sizeof(s[0]))
................
strncpy(s1.from_str,src,_countof(s1.from_str) - 1);
strncpy(s1.from_str,src,100)代码>
为什么在函数中使用100
,from_str和src都分配了10个连续的字节,但您正在复制100个字节,这将导致seg。过失
像这样使用,
strncpy(s1.from_str,src,10)代码>我可以向您指出手册页、网站等,但最终重要的是C标准本身。作为标准运行时库的一部分,C99-§7.23.2.4将使用和行为定义为:
#include <string.h>
char *strncpy(char * restrict s1,
const char * restrict s2,
size_t n);
其中N
是dst
缓冲区的硬长度,单位为字符,大于或等于1
。请注意,dst
也可以是动态分配的内存指针:
char *dst = malloc( N * sizeof(char) );
strncpy(dst, src, N-1);
dst[N-1] = 0;
使用上述方法,您将始终在dst
处有一个以null结尾的字符串。如果源字符串长度小于指定的目标缓冲区长度,strncpy()
将使用空字符尾部填充缓冲区的其余部分,直到复制的源字符+尾部填充的空字符总数等于n
,并且最终语句是多余的。如果源字符串长度等于或大于目标缓冲区长度,strncpy()
将在达到N-1
字符后停止复制,并且final语句在缓冲区末尾设置空字符。这将导致原始源的前缀字符串“缩减”,但最重要的是,它确保您不会使用稍后扫描终止符的字符串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个字符的动态字符串执行此操作。但此处src字符串的大小小于dest字符串的大小,而N大于src和dest字符串的大小。@icepack,因为from_str之后的90个字节(内存可能不属于您)被覆盖。然后它取决于编译器设置/OS。。。发生的事情是正确的,但答案没有具体说明这一切,它只是参考文献的一个副本,我只是在瞎混。这是在LINUX机器上发生的,但我在另一台UNIX机器上没有遇到任何seg故障。您认为它应该尝试做什么,以及它做什么是两件完全不同的事情。此seg故障发生在一台LINUX机器上,但不会发生在另一台UNIX机器上。为什么会这样?@HimanshuGupta:超出分配内存的写入是一种未定义的行为(UB),分段错误是众多UBs中的一个@HimanshuGupta:如果答案有帮助,请尝试投票并接受错误answer@HimanshuGupta当前位置在引擎盖下发生的事情是,strncpy在复制位置之后的任何内容上都进行了写入。这可能取决于您定义的变量,编译器如何在内存中布局数据,如果它删除了一些变量,因为它知道它们不存在
strncpy(s1.from_str,src, 100); // length parameter is wrong.
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;