简体   繁体   English

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

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

I try to implement a simple program that returns a reversed copy of string.我尝试实现一个返回字符串反向副本的简单程序。 Everything went well except a Segmentation fault at the end,.一切都很顺利,除了最后的分段错误。 It I comment the last free(), nothing looks wrong but I know it is not right.我评论了最后一个 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)

I tried to figure out from couple of question but in vain.我试图从几个问题中弄清楚,但徒劳无功。 Can someone help??有人可以帮忙吗??

In your main() function you pass your revStr() function an argument out of type char * .在您的main() function 中,您将revStr() function 传递out char *类型的参数。

out is empty and points to nothing. out是空的,并且什么都没有。

So when your revStr() function tries to append/change whatever out is pointing to (nothing in this case) with the line因此,当您的revStr() function 尝试使用该行附加/更改out指向的任何内容(在这种情况下没有任何内容)时

newStr[*idx] = *str;

It leads to a segmentation fault.它会导致分段错误。

Another problem is that as a result of out being empty, the call另一个问题是,由于out为空,调用

free(out);

becomes dangerous and leads to undefined behaviour.变得危险并导致不确定的行为。

In order to fix this you can allocate memory for out with malloc() .为了解决这个问题,您可以使用malloc()分配out

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

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

Also you should add a NUL terminator \0 to the end of out your string signify the end.此外,您应该在字符串的末尾添加一个 NUL 终止符\0表示结束。

out[in_size] = '\0';

Note:笔记:

When allocating memory for out , it is best to do it inside main() .out分配 memory 时,最好在main()内部进行。 Calling malloc() multiple times inside a recursive function is probably not something you want.在递归 function 中多次调用malloc()可能不是您想要的。

Thanks to @RetiredNinja for an useful reference.感谢@RetiredNinja 提供有用的参考。 I figured out my problem and even found myself made more unaware mistakes.我发现了我的问题,甚至发现自己犯了更多不知情的错误。 Since no one provides a correct and complete answer, I answer my question.由于没有人提供正确和完整的答案,我回答我的问题。

First of all, this is my personal practice on recursion.首先,这是我个人关于递归的实践。 If you are looking for a good example on reversing string.如果您正在寻找一个关于反转字符串的好例子。 This one is definitely NOT!!这个绝对不是!!

First mistake.第一个错误。 When I declared the out pointer, I thought it is a null pointer.当我声明 out 指针时,我认为它是一个 null 指针。

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

As matter of fact, it is NOT.事实上,它不是。 It is initialized with platform-dependent default value.它使用与平台相关的默认值进行初始化。 This explains why a free() call on it will cause segmentation fault.这解释了为什么对其进行free()调用会导致分段错误。 It is not dynamically allocated, therefore can not be freed.它不是动态分配的,因此无法释放。

Second mistake.第二个错误。 According to the idea of "passed by (copy of) values".根据“通过(复制)值”的想法。 When the pointer out was passed as parameter newStr , the pointer newStr holds same address value as out .当指针out作为参数newStr传递时,指针newStr保存与out相同的地址值。 However the address value in out remained unchanged when I changed the value in newStr to a newly allocated memory address from malloc() .但是,当我将newStr中的值更改为从malloc()新分配的 memory 地址时, out中的地址值保持不变。 My code never utilized the dynamically allocated memory.我的代码从未使用过动态分配的 memory。 The pointer to it lost after the recursive call creating it ended.在创建它的递归调用结束后,指向它的指针丢失了。

Third and an unattempted mistake.第三,一个未曾尝试的错误。 Despite not utilizing the dynamically allocated memory, my code is still able to print out another string stored in another memory segmentation.尽管没有使用动态分配的 memory,我的代码仍然能够打印出存储在另一个 memory 分段中的另一个字符串。 This is because my platform(gcc on ubuntu18) doesn't enforce a strict prohibition on variables boundary.这是因为我的平台(ubuntu18 上的 gcc)没有严格禁止变量边界。 The declaration char * out;声明char * out; only allocated a memory space to hold a char and a pointer to it.只分配了一个 memory 空间来保存一个字符和一个指向它的指针。 My code accidentally accessed the memory space beyond the declared char .我的代码意外访问了声明的char之外的 memory 空间。 This is considered unsafe and may cause segmentation fault right away on other strict platforms.这被认为是不安全的,可能会在其他严格的平台上立即导致分段错误。

first of all you have to write malloc (memory allocation to out), to do this you need to count the length of the string, then there is a mistake in revStr, you have to subtract at the end of the function, and finally you have to free allocated memory: so you have to write:首先你要写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