我有以下代码:
typedef struct{
char *name;
int age;
} person_t;
person_t
read_person(void);
int main(){
person_t Peter = read_person();
printf("%s %d\n", Peter.name, Peter.age);
}
person_t
read_person(void) {
person_t a;
a.name = "Peter";
a.age = 18;
return a;
}
因此,在函数read_person中,返回struct person_t。我想知道在函数完成时是否会释放数组a.name,因为“a”是一个局部变量。
事实证明,程序运行时会打印以下行
Peter 18
表示未释放a.name。有人可以为此提供解释吗?
答案 0 :(得分:2)
当您从a
返回read_person
时,它会复制内容。一旦程序离开a
,就会删除局部变量read_person
的存储,因为它是一个自动变量。
name
是一个指针,它将指向一个字符串文字"Peter"
,它具有静态存储持续时间,这意味着它将持续程序的生命周期,指针不需要{{1 }}编。请注意,尝试修改字符串文字是未定义的行为,因此您无法修改free
的内容。
如果另一方面name
指向name
内存,则需要malloc
。或者,您在free
中声明了一个局部变量,例如:
read_person
并且您已为此分配 char arr[] = "Peter" ;
,那么您将有未定义的行为,因为一旦您离开a
,arr
将不再存在。
答案 1 :(得分:1)
首先,name
不是数组,它是指向char
的指针,准确地说,指向字符串文字"Peter"
。字符串文字有静态存储,随时可以访问它们。
其次,a
是一个局部变量,但是你返回struct
而不是一个指针,所以a
的值被赋给变量{{1在Peter
中可以访问它。
答案 2 :(得分:1)
我想知道在函数完成时是否会释放数组a.name,因为“a”是一个局部变量。
read_person
未返回对局部变量的引用。而是返回一份副本。所以,程序已定义了行为。
"Peter"
是字符串文字,具有静态存储持续时间。
答案 3 :(得分:1)
假设我们使用的是32位机器,因此指针和整数都是4个字节。那么你的结构大小是8个字节(可能更多,但我正在简化)。
在编译时,在静态内存中留出一个位置,其中有足够的空间来容纳6个字符'P', 'e', 't', 'e', 'r'
和零空值。 'P'
的位置将是一些地址,如A1。此数据位于静态存储器。
在运行时间:
首先main()
放在堆栈内存上
然后在堆栈上保留8个字节,这是名为peter的变量
然后将read_person()
放到堆栈上
然后将另外8个字节放入堆栈;这是名为a
的变量
然后将值A1放入a
的前4个字节中
然后将值18放入a
的后4个字节中
然后函数返回。返回时:a
处堆栈中的整个8个字节被复制到peter
的堆栈中。然后将read_person
从堆栈中取出
所以现在peter的前4个字节包含值A1。第二个4字节包含18.
然后将printf
语句放到read_person
所在的堆栈中。 4字节值A1和4字节值18也被放到堆栈上以供printf
使用
print语句就是这样,并且从堆栈中取回,就像给出的参数一样
Main现在已经完成,它从堆栈中取出,堆栈现在又空了。
注意从堆内存中没有分配任何内容。在任何时候,程序都没有要求操作系统从堆中为我们提供空间以使用malloc
或类似的调用。因此,没有什么可以自由的。
答案 4 :(得分:1)
是和否。我认为你在这里缺少的是从函数返回调用的隐式复制操作。 person_t a
确实存在于read_person()
的堆栈框架上。但是,当您return a
时,a
中的值会按成员方式复制到位于person_t Peter
堆栈框架中的main()
,因为分配({{1} }})。复制完成后,Peter = read_person()
堆栈帧中的person_t a
对象确实被释放(但不是递归的 - 它不会相当于read_person()
,我认为你是关心)。
根据您的优化设置和编译器的使用年限,可能会更复杂,将free(a.name)
复制到临时未命名的a
中,然后将其复制到person_t
}。但是,许多编译器可以轻松优化额外的副本。
事实上,它甚至可能比这更简单 - 如果这是整个程序,编译器可以认识到这是Peter
的唯一调用,并选择{ {1}}将该函数放入read_person()
,之后进一步优化可能会注意到inline
和main()
可以合并到一个对象中,在这种情况下a
将有效地构建Peter
到位,甚至不会有read_person()
...
答案 5 :(得分:-1)
您要问的是可变范围。你是正确的a
是在read_person
的范围内声明和初始化的,但是通过将它返回到main函数中的变量,你现在将它带入main()
范围。主要退出时,它将超出范围。