[英]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.