我在SO中看到了很多关于得到分段错误的问题,我认为在这里引用这些问题会很棒,这个问题会引起一些导致分段错误的问题。我的答案发布在下面。
正如在一些答案中写的那样 行为未定义所有情况, 虽然很多人都认为他们是 细分错误,所以这个问题是关于是什么原因造成的 “症状”。
在下面的例子中,当我运行程序时出现分段错误,你能确定原因吗?
1)
char *str = "foo";
str[0] = 'b'; // << Segfault hre
2)
char str[] = "foo";
char *newStr = malloc(strlen(str));
strcpy(newStr, str);
free(newStr); // << Segfault here
3)
char *str = malloc(4 * sizeof(char));
str = "foo";
free(str); // << Segfault here
4)
char *str = malloc(4 * sizeof(char));
strcpy(str, "foo");
free(str);
if (str != NULL)
free(str); // << Segfault here
5)
char *str = "something and then foo";
printf("%s", str[19]); // << Segfault here
6)
typedef struct {
char *str;
}st;
...
st *s;
s = malloc(sizeof(st));
s->str = malloc(5);
free(s);
free(s->str); // << Segfault here
答案 0 :(得分:9)
您的所有示例都会导致未定义的行为,这可能会导致崩溃(或者可能根本不会造成任何伤害)。
您不能更改字符串文字。 (参见例如here)
您忘记为终止空字节分配存储空间,执行malloc(strlen(str) + 1);
你在没有从malloc(或类似函数)获得的指针上调用free()。当你使str
指针指向一个字符串文字时,你已经丢失了指向malloc和内存泄漏的内存的指针。
你在同一个指针上调用free()两次,这是未定义的行为。
printf格式字符串中的%s告诉printf该参数是一个字符串(指向一系列nul终止字符的char *)您传递的是char,而不是字符串。如果要打印字符串的后缀,请使用printf("%s", &str[19]);
您传入了一个指向free()的无效指针,您已经免费s
,以后执行s->str
时无法取消引用它。撤消释放的顺序:free(s->str); free(s);
答案 1 :(得分:4)
案例1:
char *str = "foo";
分配文本段中字符串的地址,该字符串是只读的,您不能像在第二行中那样写入它:str[0] = 'b';
。
如果要修改文本,请使用char str[] = "foo";
,它将在堆栈上创建一个字符数组,并将其指针指定给str。
案例2:
strlen
返回结束时没有'\0'
字符的字符串的长度,因此strlen("foo") = 3
,而strcpy
复制包含'\0'
字符的字符串,所以它复制比您分配的字节多。
案例3:
与情况1一样,str = "foo";
将地址“foo”分配给str
,这意味着您丢失了已分配内存的地址,str
现在包含指向文本段的指针你不能free
因为它不在堆上,而且它是一个只读存储器。
案例4:
free
函数不会将NULL
分配给作为参数接收的指针(因为它没有地址,所以不能这样做)。您正试图在已经free
d。
free
案例5:
str[19]
是char
,而不是char指针,"%s"
需要字符串,意思是char *
。在许多平台上被视为地址,这个字符是非法地址。 printf()
不会检查收到的参数。
案例6:
在s->str
s
之后使用free
是错误的。正确的用法是先拨打free(s->str);
,然后拨打free(s);
。在free
容器之前释放内部分配的内存。
答案 2 :(得分:3)
free()
传递未通过malloc()
获取的指针free()
无效指针printf()
格式说明符与实际参数类型之间的不兼容性free()
无效指针未定义的行为可以通过“分段错误”表现出来,但这绝不是必需的结果。任何事情都可能发生:)
答案 3 :(得分:1)
答案 4 :(得分:1)
3:“foo”是一个常量字符串,不是动态分配的。
旁注:这也是内存泄漏。