簡體   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