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