我试过这段代码!我无法理解它是如何运作的。
int main()
{
char *s1;
s1=malloc(sizeof(char)*20);
strcpy(s1,"main");
printf("%s\n",s1);
func(s1);
printf("After call %s\n",s1);
return 0;
}
void func(char *s2)
{
//free(s2);<--------------(this is what I'm talking about)
s2=malloc(sizeof(char)*25);
strcpy(s2,"func");
printf("fun---%s\n",s2);
}
输出:
main
fun---func
After call main
但是如果在func()中我添加了注释行输出
Outout:
main
fun---func
After call main
我想知道整个事情是如何运作的。我的意思是s1
是char*
。分配后,它指向一块内存。在C中,一切都是按价值传递的。因此,当我们传递它时,将在(stack)main
的本地范围内创建另一个变量,该变量保存分块内存的地址(即s1
包含相同的值)。
s1
中的main()
无法反映出变化。由于s1
永远不会改变。printf()
之后在func()
中获取main中的垃圾值。这是正确的想法吗?如果没有,请明确这个概念。在Windows中,它给出了我告诉你的结果。但在Linux中,它以某种方式反映了这种变化。
我错过了什么?
答案 0 :(得分:5)
你(大部分)都是正确的。
在函数中释放s2
(以及s1
),然后在返回s1
时使用main()
,这就是所谓的未定义行为。
你不应该这样做,因为标准规定任何任何事情都可以发生,而且,这就是问题所在,&#34;任何事情&#34;包括它可行的可能性。
为什么它的工作几乎可以肯定,因为没有其他人再次分配该内存块并覆盖其中的数据,因此它仍包含最初的内容。
如果您在main()
之间的func()
和s1
的打印之间插入了:
char *s3 = malloc(10000);
strcpy (s3, "Yoohoo, I'v changed");
然后你可以好发现打印s1
会给你一个不同的结果。
或者,既然它是UB,也许不是: - )
建议避免未定义的行为,即使它似乎有效。更改编译器,编译器标志或代码顺序,甚至在蓝色月亮上编译可能会改变代码以意想不到的方式工作的方式。
如果要传回函数中分配的指针(除了使用return
之外),可以使用双重间接:
void allocStr (char **pStr) {
free (*pStr);
*pStr = malloc (1000);
}
:
char *xyzzy = NULL;
allocStr (&xyzzy);
这是你在C中传递引用的方式。
答案 1 :(得分:3)
(这并没有回答你的问题,但要发表评论还有很多。)
要使它在没有undefined behavior的情况下工作,你需要通过引用传递指针(或者更确切地说,因为它在C中不可能,你必须模仿传递引用语义)。这可以通过将指针传递给指针来完成,然后您可以在函数中更改它。
像
这样的东西void func(char **s2); // Pointer to pointer
int main(void)
{
char *s1 = malloc(20); // No need for `sizeof` as `sizeof(char)` is always 1
strcpy(s1, "main");
func(&s1); // Note use of `&` address-of operator
}
void func(char **s2)
{
free(*s2); // Note use of dereference operator `*`
*s2 = malloc(20);
strcpy(*s2, "func");
}
答案 2 :(得分:0)
整个过程与你说的完全一样。在解除引用陈旧指针(s2指向释放的内存)时第二次运行时没有获得垃圾的原因是,系统还没有重用内存。