C 返回指向静态变量的本地指针
这是密码C 返回指向静态变量的本地指针,c,static,C,Static,这是密码 char *foo() { static char s[10] = "abcde"; return s; } char *bar() { char *c = foo(); return c; } int main() { printf("%s\n", bar()); } 通常,像我在bar中那样返回本地指针是错误的,但是现在c指向foo返回的staticvar,在bar中返回本地varc是否正确 我试过了,它printf是正确的值,但我不
char *foo()
{
static char s[10] = "abcde";
return s;
}
char *bar()
{
char *c = foo();
return c;
}
int main()
{
printf("%s\n", bar());
}
通常,像我在bar
中那样返回本地指针是错误的,但是现在c
指向foo
返回的static
var,在bar
中返回本地varc
是否正确
我试过了,它printf
是正确的值,但我不明白它是如何工作的。我想,当bar()
结束时,varc
应该消失,这应该使printf
打印未定义的内容,对吗
跟进
char*c
是一个局部变量,如果char*c=“abcde”
,我假设:c
是一个驻留在函数堆栈中的局部变量,而“abcde”
是一个驻留在常量区域(堆的一部分?)的常量变量,因此当bar()
完成时,c
消失,但“abcde”
仍保留在堆中,对吗?变量c
只是一个指针。从函数返回本地指针并没有错,您一直都在这样做。例如,当您在指针中存储malloc
的结果时,指针是本地的,但它指向的存储不是本地的。但是,返回指向本地存储的指针是错误的。因为在您的示例中c
从不指向本地分配的数据,所以您的代码可以正确地运行
编辑(响应后续行动)
“abcde”是一个常量变量,它位于常量区域(堆的一部分?)
常量区域通常不是堆的一部分,它是一个单独的arrea,通常与存储程序机器代码的区域相邻
c消失了,但“abcde”仍然在堆中,对吗
“abcde”保留在常量区域中,而不是堆中,但概念是正确的:指向该常量的指针在程序的整个运行期间保持有效。返回c
的值,即foo()
即s
即abcde
的地址。bar
返回的是执行char*c=foo()操作时存储该值的空间代码>
所以,是的,这是正确的。你的直觉是正确的,但你似乎遇到的问题是:
C中有三种类型的存储
自动(正常的本地存储)位于堆栈上,返回函数后指向此数据的指针不再有效
Dynamic(想想malloc),在调用free()后,它位于堆中,指向该数据的指针不再有效
静态的存在于数据段中(因此不会消失)
由于s是一个静态变量,它将持续整个程序生命周期。所以,不,当富回来时,它不会消失
编辑:我应该补充一点,也有寄存器,但大多数编译器基本上都忽略了这一点。函数中的静态局部变量将保留在内存中,直到应用程序结束,并且在函数返回时不会消失。这就是为什么在printf
中,即使在函数foo
之外,使用指向静态变量的指针也能提供有效数据的原因
如果局部变量不是静态的,那么当函数返回时变量消失时,相同的测试将失败。Aha,是的。但很抱歉,我想做的只是另一个“后期编辑”。@Alcott我编辑了答案以响应后续操作。顺便说一句,我在哪里可以获得有关常量区域的更多详细信息?从这里开始,然后从这里开始@Alcott是一个快速参考,解释了运行程序的各种内存段。字符常量通常存储在代码段中,尽管这取决于体系结构:有时,在程序启动时,字符常量会复制到数据段。因此,当c
消失时,“abcde”仍然存在,因此的地址“abcde”
是有效的,对吧?我想你需要理解函数返回后变量“消失”的含义。看看汇编代码,使用gcc test.c-O0-S编译。register
不会被忽略。获取寄存器的地址
变量违反了约束,这正是它现在的目的,告诉编译器如果您获取了这样一个变量的地址,就会收到警告。这是真的。然而,这可能是历史原因造成的。请参见“否”,它只是优化的一个平均值,例如restrict
关键字。它也避免了你在回答中所说的错误。你不能记下它的地址,所以你永远不会想把它还给打电话的人。如果只是出于历史原因,委员会可能会宣布它从那时起就过时了,这是因为它的一些特性。让我们明确一点,C的全球标准是70年代的ANSI C。当时的计算机,尤其是编译器更为原始。登记处当时有它的位置。至于寄存器的存在是为了防止程序员犯一些愚蠢的错误。首先,这与c语言相反,其次,它只在那里,因为寄存器中的数据不能获取它的地址。此外,C++用户想要贬低它。看,你错了,ANSI C是1989年第一次标准化的,标准化这一方面确实是一个很大的优势。既然你提到标准(而不是市场份额或诸如此类的东西),那么从去年12月开始,C的当前标准是C11。它是由国际标准组织ISO给出的。在这个问题上,它不是像static char*foo()
而不是char*foo()
,因为foo的返回类型是static char*
。它可能会抛出:警告:“foo”[-Wmissing prototype]没有以前的原型。