我是C的初学者。我有一个程序如下:
int main()
{
char* func();
char *c;
c = func();
printf("%s", c);
}
char* func()
{
char *ptr = "OK";
return ptr;
}
众所周知,ptr
是func()
的局部变量,是一个指针。范围是本地的。
但是当ptr
返回给调用者main
时,它仍然有效,并且在打印c
时,它会打印"确定"。
这怎么可能?在哪个内存段中存储ptr
;堆栈还是堆?
答案 0 :(得分:7)
这是使用指针时的内幕(注意指针就像名字所暗示的那样,就像手指指向某个东西)。
让我们分解您的代码并逐步理解它。 在main函数中,您声明了一个字符指针* c
char *c;
然后你这样做了:
c = func();
告诉c指针指向func()指向的内容。
让我们来看看你的功能
char* func()
{
char *ptr = "OK";
return ptr;
}
第一行再次声明一个字符指针ptr,并为该地址指定“OK”(注意:指针只指向某个存储器地址)。所以现在,该地址包含字符串“OK”(或者更准确地说,是一个char数组)。
然后返回ptr,这是“OK”所在的地址。请注意,因为ptr是在func()中声明的,所以它是一个局部变量。因此,一旦返回,它将从堆栈(poof!Gone)中删除。
但是,因为在你的main()中:
c = func();
变量c指向存储“OK”的地址。因此,即使变量ptr不再存在,变量c也知道它在哪里,并且仍然可以访问“OK”。
回答你的问题:
答案 1 :(得分:4)
让我们暂时忘记堆栈/堆栈。我们来聊聊C。
ptr
之外的本地变量func
不存在,因此调用者不能且不应引用。
但是C doesn't do pass by reference。一切都是通过价值传递的。 func
会将ptr
中存储的值返回给其调用者。就像你会返回int
或任何其他类型的值一样。
因此,对于您的示例,ptr
的值是名为"OK"
的字符串文字的地址。并且string literals are valid during the entire scope of the program。因此func
返回字符串文字的地址,允许在程序中的任何位置取消引用。
为了更清楚,func
相当于:
const char * func (void)
{
return "OK";
}
这就是为什么一切都很好。
知道以下情况还可以:
const char * func (void)
{
char *ptr = "OK";
return ptr;
}
这不是:
const char * func (void)
{
char ptr[] = "OK";
return ptr;
}
不行,因为现在你正在返回指向 local 到func
的数组的指针。
还有一个小问题。它应该是:const char * func ()
,因为"OK"
不允许修改。
答案 2 :(得分:2)
当您调用该函数时,其所有局部变量和返回地址都会推送到堆栈。所以ptr将在堆栈中,但是“OK”-string在常量数据部分。当您从func
返回时,ptr
的值已分配给c
变量,ptr
不再存在(实际存在),但其值存储在{ {1}}。
答案 3 :(得分:1)
文本"OK"
存储在可执行文件的常量数据部分中(在启动进程时将其加载到内存中)。虽然ptr
是局部变量,但编译器会将其初始化为指向存储在其他位置的"OK"
。当您将ptr
返回给调用者时,指针仍然指向相同的"OK"
。
答案 4 :(得分:1)
如果您指的是字符串OK
的存储位置,则其存储在内存的 code部分中,而ptr
则存储在堆栈。
由于OK
返回了其地址,因此func()
在代码部分的位置仍然可以访问。
此外,代码部分为只读。这就是为什么其他答案建议将函数声明为:
的原因const char * func ()
这确保返回的地址所指向的值不可修改。 (指向常量的指针)
答案 5 :(得分:0)
ptr
保存常量数据部分中"OK"
数据的地址。这是返回的地址。不是ptr
的地址即使ptr
不再存在,"OK"
仍然存在
答案 6 :(得分:0)
char *ptr = "OK";
- 该语句将为变量ptr
分配4个字节(如果它是32位机器),它将保存字符串文字OK
的地址。现在ptr
具有字符串OK
的起始地址(4字节)(实际上是3个字节,包括\0
)。这3个字节的字符串OK
将位于文本段中,这是一个只读数据。你也不能修改。例如,在这种情况下ptr[0] = 'T'
是不可能的。文本段中的字符串文字(3个字节)将在整个过程的生命周期中存在。但是一旦控件来自函数func
,则将释放为变量ptr
分配的4个字节以保存字符串文字的地址。你也可以写下你的函数func
,如下所示
char* func()
{
return "OK";
}
更改您的功能,如下所示
char* func()
{
char ptr[] = "OK";
return ptr;
}
这次将为变量ptr
分配3个字节以在本地存储字符串。这个范围只在函数内。
答案 7 :(得分:0)
char* func()
{
char* ptr;
ptr = (char*)malloc(100);
strcpy(ptr, "OK");
return ptr;
}