我只是在用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。但是在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)
为什么在这里发生段错误。
有人可以帮我从这里出去吗。
最佳答案
我可以指出您的手册页,网站等,但是最终重要的是C标准本身。作为标准运行时库的一部分,用法和行为在C99-§7.23.2.4中定义为:
#include <string.h>
char *strncpy(char * restrict s1,
const char * restrict s2,
size_t n);
这里有很多隐含的信息,最重要的是:如果源字符串长度(不包括其空字符终止符)达到或超过了指定的目标缓冲区长度,则
strncpy()
将而不是终止目标字符串。此外,尽管在标准中有明确规定(请参见上文),但它仍然使我感到困惑,有多少工程师不知道
strncpy()
用空字符尾填充目标字符串缓冲区,直到当源字符串长度较小时达到指定长度n
为止比目标缓冲区的大小大。得出以下不可避免的结论:strncpy()
API将始终将n
字符写入目标缓冲区引用的地址。 在您的情况下,由于目标缓冲区只有10个字符宽,因此您将在可写内存的定义端之后再写入90个字符,从而进入未定义行为的领域。
此时,您必须问自己“那有什么用?”有一个基本的用例。它使您可以将多达
n
字符复制到目标缓冲区,并具有可预测性,因为您知道自己不会超出n
字符。时期。但最终,您需要一个以空值结尾的字符串,因此正确的用法是这样的:char dst[ N ];
strncpy(dst, src, N-1);
dst[N-1] = 0;
其中
N
是dst
缓冲区的硬长度,以char为单位,并且大于或等于1
。注意dst
可能也是动态分配的内存指针:char *dst = malloc( N * sizeof(char) );
strncpy(dst, src, N-1);
dst[N-1] = 0;
有了上述内容,您将在
dst
处始终有一个以空值终止的字符串。如果源字符串长度小于指定的目标缓冲区长度,则strncpy()
将用空字符尾部填充其余缓冲区,直到源字符复制+尾部填充空字符总数等于n
,最后声明是多余的。如果源字符串的长度等于或大于目标缓冲区的长度,则到达strncpy()
字符后,N-1
将停止复制,并且final语句在缓冲区的末尾设置一个空字符。这将导致原始源的“缩减”前缀字符串,但是最重要的是,它可以确保您不会在以后扫描终止符的字符串API调用中超出目标缓冲区的边界。上述技术的实用性始终值得商bat。我是C++专家,所以
std::string
可以使我免于这种疯狂。但是现实是这样的:有时您会关心src
是否未完全复制到dst
;有时候你不知道。有用之处在于和视情况而定。对于在UI中显示字符串数据,这(可能)无关紧要。对于复制要用于关键数据的字符串,局部前缀-子字符串将是 Not Acceptable 。当警察向“小约瑟夫·约翰逊”签发逮捕证时,将有一些解释要做,当他的父亲(“约瑟夫·约翰逊”)被送进 jail 时,因为签发证件软件的名称缓冲区只能容纳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;
有关如何对长度为N个字符的动态字符串执行此操作,请参见先前的用法。
关于c - strncpy导致段错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14065391/