函数strncpy导致段错误 [英] strncpy leading to segmentation fault

查看:786
本文介绍了函数strncpy导致段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是瞎搞与函数strncpy。

我的计划是这样的。

  typedef结构
{
    焦炭from_str均被[10];
}测试;main()的
{    测试S1;
    memset的(安培; s1,0,sizeof的(试验));
    炭的src [10] =himansh;
    焦炭DEST [10];    memset的(DEST,0,10);
    SRC [3] ='\\ 0';    的printf(src为%s和strlen的为%d \\ n,
            SRC,strlen的(SRC));    fflush(标准输出);    函数strncpy(s1.from_str,SRC,100);    的printf(s1.from_str为%s,SRC为%s \\ n,
            s1.from_str,SRC);
    返回1;}

下面之前,我做我函数strncpy添加的SRC字符串\\ 0字符的SRC长字符串变成3,目的是数组大小为10。但在函数strncpy我已经把字节数为复制为100。

这意味着我的源字符串为空终止。现在函数strncpy像任何字符串函数应该尝试即使我提供的字节数是大于3(在这种情况下,100)仅复制3个字节。它这样做,但我得到一个分段错误了。

我的结果如下所示

  src为他和strlen的是3
s1.from_str是他,src为他
分段错误(核心转储)

这是为什么分段故障发生在这里。

任何一个可以帮助我在这里。


解决方案

我可以指出你的男人网页,网站等,但最终重要的是C标准本身。作为标准运行时库的一部分,使用和行为在C99-§7.23.2.4定义为:

 的#include<&string.h中GT;
字符*函数strncpy(字符*限制S1,
      为const char *限制S2,
      为size_t n)的;


  

说明
  在函数strncpy 函数将不超过n个字符(字符跟随一个空字符不复制)从阵列指向S2到阵列指向
  S1。如果复制操作是重叠的对象之间,行为是不确定的。
  如果阵列指向S2是一个字符串是超过n个字符短,空字符追加到数组中的副本指向S1,直到所有的n个字符已被写入。


  
  

返回
  在函数strncpy 函数返回s1的值。


有是的显著的隐含信息,在这里,最重要的是:函数strncpy()不会终止您的目的地字符串,如果源字符串长度(不包括其空字符终止)达​​到或超过指定的目标缓冲区长度)一个空字符。

此外,尽管在标准明确规定(见上文),它继续混淆了我很多的工程师怎么都没有意识到,函数strncpy()尾罢了的空字符,直到指定长度的目标字符串缓冲区 N 当源字符串长度达到的的比目标缓冲区大小。这得出以下必然的结论:

函数strncpy() API将总是写 N 字符由目标缓冲区中引用的地址。

在你的情况,因为目标缓冲区只有10字符宽,你写过去写存储器的定义,最终90个其他字符,从而走进中的未定义行为的土地

在这一点上,你必须问自己:这样有什么用?有的一个可以说是基本用例。它可以让你复制到 N 字符与知道你的predictability目标缓冲区不会溢出过去 N 字符。期。不过说到底,你想有一个空值终止字符串,所以的的正确用法是这样的:

 字符DST [N];
函数strncpy(DST,SRC,N-1);
DST [N-1] = 0;

其中, N DST 缓冲区的硬长度字符,是大于 - 或 - 等于 1 。需要注意的是 DST 可能只是-AS-不失为一个动态分配的内存指针:

 的char * DST =的malloc(N * sizeof的(炭));
函数strncpy(DST,SRC,N-1);
DST [N-1] = 0;

有了上面,你会的总是的具有 DST 一个空结尾的字符串。如果源字符串的长度的比指定的目标缓冲区长度较小,函数strncpy()将尾填充空字符缓冲区的誓不罢休共源字符复制的+尾填充空字符等于 N ,和最后陈述是多余的。如果源字符串长度的等于或大于的大于目标缓冲区长度,函数strncpy()将停止复制一次ñ -1 字符都达到了,最后陈述在缓冲区的末尾设置一个空字符。这将导致原始出处的切下preFIX字符串,但最重要的,它可以确保你不会与扫描一个终止以后串​​API调用超出目标缓冲区的边界。

以上技术的实用性始终是值得商榷的。我是一个C ++的家伙,所以的std ::字符串保存所有这种疯狂我快乐的自我。但实际情况是这样的:有时候,你介意的src 中是不可复制其的全部 DST ;有时候你不知道。用处的非常情境依赖。对于presenting字符串的数据在UI这不会(可能)的事情。复制的字符串用于关键数据,一个partial- preFIX-子不会被接受。当警方发出逮捕令,以约瑟夫·约翰逊,会有一些解释这样做时,他的父亲(约瑟夫强生)被拖进监狱,因为权证发放软件的名称,缓冲区只举行了15个字符

所有这一切都说过,你分段故障归结为下面的语句:

 函数strncpy(s1.from_str,SRC,100); //长度参数是错误的。

回想一下上面的大胆的声明:函数strncpy()将永远写 N 字符地址由目标缓冲区引用。。这意味着上述code将总是写100个字符的目标缓冲区,而你的情况是只有10个字符宽,因此不确定的行为和可能的 KER-热潮

如果目标缓冲区是一个固定长度的字符数组通过执行以下操作

纠正这个:

 函数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;

请参阅如何做到这一点的长度`ñ字符的字符串动态的先前使用。

I am just messing around with strncpy.

My program looks like this

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;

}

Here before I do strncpy I have added a "\0" character in "src" string, length of "src" string becomes 3 , destination array is of size 10 .But in strncpy I have put number of bytes to be copied as 100.

This means my source string is NULL terminated. Now strncpy like any string function should try to copy only 3 bytes even if the number of bytes I provide is more than 3 (in this case 100). It does that, but I get a segmentation fault too.

My result is shown below

src is him and strlen is 3
s1.from_str is him , src is him
Segmentation fault (core dumped)

Why is this segmentation fault happening over here.

Can any one help me out here.

解决方案

I could point you to man pages, websites, etc, but ultimately what matters is the C standard itself. As part of the standard runtime library, the usage and behavior is defined in C99-§7.23.2.4 as:

#include <string.h>
char *strncpy(char * restrict s1,
      const char * restrict s2,
      size_t n);

Description The strncpy function copies not more than n characters (characters that follow a null character are not copied) from the array pointed to by s2 to the array pointed to by s1. If copying takes place between objects that overlap, the behavior is undefined. If the array pointed to by s2 is a string that is shorter than n characters, null characters are appended to the copy in the array pointed to by s1, until n characters in all have been written.

Returns The strncpy function returns the value of s1.

There is significant implied information here, the most important being: strncpy() will NOT terminate your destination string with a null character if the source string length (not including its null character terminator) meets or exceeds the specified destination buffer length).

Furthermore, though clearly specified in the standard (see above), it continues to confound me how many engineers are NOT aware that strncpy() tail-fills the destination string buffer with null characters until the specified length n is reached when the source string length is less than the destination buffer size. This draws the following inescapable conclusion:

The strncpy() API will ALWAYS write n characters to the address referenced by the destination buffer.

In your case, because the target-buffer is only 10-chars wide, you're writing 90 additional characters past the defined-end of writable memory, and thus walking into the land of undefined behavior.

At this point you have to be asking yourself "So whats the use?" There is an arguably fundamental use-case. It allows you to copy up to n chars to the target buffer with the predictability of knowing you won't overrun past n chars. Period. Ultimately, though, you want a null-terminated string, so the proper usage is this:

char dst[ N ]; 
strncpy(dst, src, N-1);
dst[N-1] = 0;

where N is the hard-length of the dst buffer in chars and is greater-than-or-equal to 1. Note that dst could just-as-well be a dynamic-allocated memory pointer:

char *dst = malloc( N * sizeof(char) ); 
strncpy(dst, src, N-1);
dst[N-1] = 0;

With the above, you will always have a null-terminated string at dst. If the source string length is smaller than the specified target buffer length, strncpy() will tail-fill the rest of the buffer with null characters until a total of source-chars-copied + tail-filled-null-characters equals n, and the final statement is redundant. If the source string length is equal to or greater than the target buffer length, strncpy() will stop copying once N-1 chars are reached, and the final statement sets a null character at the end of the buffer. This results in a "cut-down" prefix string of the original source, but most important, it ensures you will NOT exceed the boundaries of your target buffer with a later string-API call that scans for a terminator.

The usefulness of the above technique is always debatable. I'm a C++ guy, so std::string saves my happy-self from all this insanity. But the reality is this: Sometimes you care if src isn't copied in its entirety to dst; sometimes you don't. The usefulness is very situationally dependent. For presenting string-data in a UI this won't (likely) matter. For copying a string to be used for critical data, a partial-prefix-substring isn't going to be acceptable. When the police issue an arrest warrant to "Joseph Johnson Jr.", there will be some explaining to do when his father ("Joseph Johnson") is hauled into jail because the name-buffer of the warrant-issuance software only held 15 chars.

All of that said, your segmentation fault comes down to this statement:

strncpy(s1.from_str,src, 100); // length parameter is wrong.

Recall the bold statement above: "strncpy() will ALWAYS write n characters to the address referenced by the destination buffer.". This means the above code will always write 100 chars to the target buffer, which in your case is only 10-chars wide, thus undefined behavior and likely ker-boom.

Rectify this by doing the following if the target buffer is a fixed-length character array:

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;

See the prior usage for how to do this for dynamic string of length `N chars.

这篇关于函数strncpy导致段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆