此问题与this并不完全相同。最受欢迎的答案here说,不能保证会保留该内存位置,但是偶然地做到了。 Where是从这段代码中获得的,它清楚地说明了将保留字符串变量。
考虑以下代码:
#include<stdio.h>
char *getString()
{
char *str = "abc";
return str;
}
int main()
{
printf("%s", getString());
getchar();
return 0;
}
此代码编译并运行无任何错误。
指针char* str
未定义为静态变量。然而,即使函数返回后,该变量似乎仍被保留。
请解释这种行为。
即使这个问题尚未得到回答或被标记为重复,我也不明白为什么这个问题得到否决。
答案 0 :(得分:2)
char * getString()... char * str =“ abc”;
您正在感到困惑。 getString()在堆栈中创建一个变量,并使其指向文字字符串。该字面量可以在任何地方,并将始终保持在该位置。根据编译器的不同,它可以在启动时在RAM中初始化,也可以在只读存储器中。 OK:如果它在RAM中,也许您甚至可以对其进行修改,但不能以正常(合法)的方式进行修改-我们应该忽略它,并将其视为不变的数据。
上面的点是该点。的确,字符串“被保留”。但是保留自动变量并非正确-可能发生,但是您不应该依赖该变量,否则会出错。按照定义,自动变量在函数返回时会被销毁,并确保它会发生。
也就是说,我看不出如何说该变量已保留。 C语言中没有机制可以查看局部变量(当前作用域之外);您可以使用调试器来实现,特别是当活动框架是getString()的框架时;也许有些调试器可以让您查看不应该在哪里,但这是另一回事。
评论后编辑
许多编译器在堆栈中创建自动(局部)变量。当函数返回时,堆栈上的数据保持不变,因为清除/破坏堆栈是通过简单地将堆栈指针移动到其他位置来进行的。因此,确认“变量似乎已保留” 是正确的。 似乎是因为实际上变量仍然存在。它似乎是 ,因为没有合法的使用方法。但是即使在这种情况下,变量仍然存在但被隐藏,编译器仍可以决定将该空间用于其他用途,或者中断可以到达并使用同一空间。换句话说,虽然auto变量在范围内,但可以保证“保留”,但是当它超出范围时,必须视为已消失。
在某些情况下,人们可以编写代码来引用超出范围的变量:这些是编译器应(有时可以)检测到的错误。
我说过,自动变量经常进入堆栈。这并不总是正确的,它取决于体系结构和编译器,但其余所有都是正确的,并且受语言规则的约束。
答案 1 :(得分:1)
str
的地址可能会更改,但它指向的内容(一旦初始化)就不会更改。
请注意,在这个简单的示例中,您可能看不到更改。如果您从不同的堆栈深度多次调用getString
并显示&str
,您将会明白我的意思。
char *getString()
{
char *str = "abc";
printf("%p", &str);
return str;
}
int main()
{
printf("%s", getString());
stackTest();
getchar();
return 0;
}
void stackTest()
{
char blob[200];
int x=0;
printf("%s", getString());
}
*(我尚未对此进行测试,根据您的编译器和设置,未使用的堆栈变量可能会被优化掉)
答案 2 :(得分:0)
C 2011(草案N1570)第6.4.5节第6段描述了源代码中的字符串文字如何变为静态对象:
然后,将多字节字符序列用于初始化一个足以包含该序列的静态存储持续时间和长度数组。对于字符串文字,数组元素的类型为 char ,并使用多字节字符序列的各个字节进行初始化。
因此,在char *str = "abc";
中,str
初始化为指向包含字符a,b和c以及一个空字符的静态数组。
然后return str;
返回此指针的值。
最后,printf("%s", getString());
将指针的值传递给printf
。至此,str
对象消失了(在C语言的计算模型中)。它不再存在。我们具有用于保留的值,但是str
对象本身已消失。但是,该值指向一个静态对象,即字符数组,printf
读取并打印该数组。
因此,您的问题的标题不正确。函数内部声明的非静态指针变量未保留。保留的只是字符的静态数组及其地址。