繁体   English   中英

为什么 free 在我的代码中导致了分段错误?

[英]Why free caused a Segmentation fault in my code?

我尝试实现一个返回字符串反向副本的简单程序。 一切都很顺利,除了最后的分段错误。 我评论了最后一个 free(),看起来没什么问题,但我知道这是不对的。

#include <stdio.h>
#include <stdlib.h>

void revStr(char *str, char *newStr, int *idx)
{
    if( *str != '\0')
    {
        *idx = *idx+1;
        revStr(str+1, newStr, idx);
        printf("char=%c int=%d\n", *str,*idx);
        newStr[*idx]=*str;
        *idx = *idx+1;
    }
    else if (*idx !=0)
    {
        printf("End Size=%d\n",*idx);
        newStr = (char*)malloc( sizeof(char) * (*idx) );
        *idx=0;
    }
}

int main(void) {
    int idx =0;
    char * in = "This is a test string.";
    char * out;

    revStr(in, out, &idx);

    printf("Out:%s\n", out);
    free(out);

    return 0;
}
char=. int=0
char=g int=1
char=n int=2
char=i int=3
char=r int=4
char=t int=5
char=s int=6
char=  int=7
char=t int=8
char=s int=9
char=e int=10
char=t int=11
char=  int=12
char=a int=13
char=  int=14
char=s int=15
char=i int=16
char=  int=17
char=s int=18
char=i int=19
char=h int=20
char=T int=21
Out:.gnirts tset a si sihT
Segmentation fault (core dumped)

我试图从几个问题中弄清楚,但徒劳无功。 有人可以帮忙吗??

在您的main() function 中,您将revStr() function 传递out char *类型的参数。

out是空的,并且什么都没有。

因此,当您的revStr() function 尝试使用该行附加/更改out指向的任何内容(在这种情况下没有任何内容)时

newStr[*idx] = *str;

它会导致分段错误。

另一个问题是,由于out为空,调用

free(out);

变得危险并导致不确定的行为。

为了解决这个问题,您可以使用malloc()分配out

size_t in_size = strlen(in);
char *out = malloc(in_size + 1);

// allocate memory for string
// and +1 for NUL terminator 

此外,您应该在字符串的末尾添加一个 NUL 终止符\0表示结束。

out[in_size] = '\0';

笔记:

out分配 memory 时,最好在main()内部进行。 在递归 function 中多次调用malloc()可能不是您想要的。

感谢@RetiredNinja 提供有用的参考。 我发现了我的问题,甚至发现自己犯了更多不知情的错误。 由于没有人提供正确和完整的答案,我回答我的问题。

首先,这是我个人关于递归的实践。 如果您正在寻找一个关于反转字符串的好例子。 这个绝对不是!!

第一个错误。 当我声明 out 指针时,我认为它是一个 null 指针。

char * out;
............
............
free(out);

事实上,它不是。 它使用与平台相关的默认值进行初始化。 这解释了为什么对其进行free()调用会导致分段错误。 它不是动态分配的,因此无法释放。

第二个错误。 根据“通过(复制)值”的想法。 当指针out作为参数newStr传递时,指针newStr保存与out相同的地址值。 但是,当我将newStr中的值更改为从malloc()新分配的 memory 地址时, out中的地址值保持不变。 我的代码从未使用过动态分配的 memory。 在创建它的递归调用结束后,指向它的指针丢失了。

第三,一个未曾尝试的错误。 尽管没有使用动态分配的 memory,我的代码仍然能够打印出存储在另一个 memory 分段中的另一个字符串。 这是因为我的平台(ubuntu18 上的 gcc)没有严格禁止变量边界。 声明char * out; 只分配了一个 memory 空间来保存一个字符和一个指向它的指针。 我的代码意外访问了声明的char之外的 memory 空间。 这被认为是不安全的,可能会在其他严格的平台上立即导致分段错误。

首先你要写malloc(内存分配到out),要做到这一点你需要计算字符串的长度,然后revStr有错误,你必须在function的末尾减去,最后你必须释放分配的 memory: 所以你必须写:

#include <stdio.h>
#include <stdlib.h>

void revStr(char *str, char *newStr, int *idx)
{
    if( *str != '\0')
    {
        *idx = *idx+1;
        revStr(str+1, newStr, idx);
        *idx = *idx-1;
        printf("char=%c int=%d\n", *str,*idx);
        newStr[*idx]=*str;
    }

}

int main(void) {
    int idx =0;
    char * in = "This is a test string.";
    char * out;

    while (in[idx])
        idx++;
    out = (char *) malloc (sizeof (char) * (idx + 1));
    if (!out) //if there is no enough memory we go to this exception
        return(12);
    out [idx] = 0;

    idx = 0;

    revStr(in, out, &idx);

    printf("Out:%s\n", out);
    if (out)
        free(out);

    return 0;
}

And the output will be:

>char=. int=21
char=g int=20
char=n int=19
char=i int=18
char=r int=17
char=t int=16
char=s int=15
char=  int=14
char=t int=13
char=s int=12
char=e int=11
char=t int=10
char=  int=9
char=a int=8
char=  int=7
char=s int=6
char=i int=5
char=  int=4
char=s int=3
char=i int=2
char=h int=1
char=T int=0
Out:This is a test string.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM