6

我是 C 的初学者。我有一个程序如下:

int main()
{
    char* func();
    char *c;
    c = func();
    printf("%s", c);
}

char* func()
{
    char *ptr = "OK";
    return ptr;
}

众所周知,ptr是一个局部变量,func()是一个指针。范围是本地的。但是当ptr返回给调用者时main,它仍然有效,当c打印时,它打印“OK”。

这怎么可能?存储在哪个内存段中ptr;堆栈还是堆?

4

8 回答 8

8

这就是使用指针时发生的事情(请注意,指针就像名称所暗示的那样,就像手指指向某物一样)。

让我们分解您的代码并一点一点地理解它。在您的主函数中,您声明了一个字符指针 *c

char *c;

然后你这样做了:

c = func();

它告诉 c 指针指向这个 func() 指向的任何东西。

让我们看看你的功能

char* func()
{
    char *ptr = "OK";
    return ptr;
}

第一行再次声明一个字符指针 ptr,并将“OK”分配给该地址(注意:指针只是指向某个内存地址)。所以现在,该地址包含字符串“OK”(或更准确地说,是一个字符数组)。

然后你返回ptr,这是“OK”所在的地址。请注意,因为 ptr 是在 func() 中声明的,所以它是一个局部变量。因此,一旦返回,它就会从堆栈中删除(噗!消失了)。

但是,因为在您的 main() 中:

c = func(); 

变量 c 指向存储“OK”的地址。因此,即使变量 ptr 不再存在,变量 c 也知道它在哪里,并且仍然可以访问“OK”。

要回答您的问题:

  • ptr 存储在堆栈中
  • 退出 func() 时 ptr 从堆栈中弹出
于 2015-06-10T10:06:37.207 回答
4

让我们暂时忘记堆栈/堆。让我们谈谈C。

局部变量ptr在外部不存在func,因此调用者不能也不应该引用它。

但是C 不会通过引用传递。一切都是按值传递的。将存储的func返回给它的调用者。就像您将返回一个或任何其他类型的值一样。ptrint

因此,对于您的示例,ptr' 值是名为 的字符串文字的地址"OK"。并且字符串文字在程序的整个范围内都是有效的。所以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;
}

这是不行的,因为现在你要返回一个指向本地数组的指针func

还有一个小点。应该是:const char * func (),因为"OK"不允许修改。

于 2012-07-14T07:22:19.670 回答
3

当您调用该函数时,它的所有局部变量和返回地址都会压入堆栈。所以 ptr 将在堆栈上,但在常量数据部分中是“OK”字符串。当您从. func_ _ptrcptrc

于 2012-07-14T05:10:30.540 回答
2

文本"OK"存储在可执行文件的常量数据部分(在进程启动时加载到内存中)。尽管ptr它是一个局部变量,但编译器将其初始化为指向"OK"存储在别处的变量。当您返回ptr调用者时,指针仍然指向相同的"OK".

于 2012-07-14T04:43:59.367 回答
1

如果您指的OK是存储字符串的位置,则它存储在内存的代码部分ptr并存储在堆栈中。

并且OKin 代码部分的位置仍然可以访问,因为它的地址正在由func().

此外,代码部分是只读的。这就是为什么其他答案建议将您的函数声明为:

const char * func ()

这确保了返回地址指向的值不可修改。(指向常数的指针)

于 2020-01-27T07:55:14.633 回答
0

ptr 本身在堆栈上是瞬态的,但它指向的不是。一种情况就像在您的 func() 中,哪个字符串文字存储在“常量数据区域”中,另一种情况是在堆上分配数据,即通过 malloc(),因此是全局的并且不会在堆栈时被销毁功能没了。

char* func()
{
        char* ptr;
        ptr = (char*)malloc(100);
        strcpy(ptr, "OK");
        return ptr;
}
于 2012-07-15T10:31:05.597 回答
0

char *ptr = "OK";- 该语句将为变量分配 4 个字节(如果它是 32 位机器),ptr它将保存字符串字面量的地址OK。现在ptr有一个字符串的起始地址(4 字节)OK(实际上是 3 个字节,包括\0)。这 3 个字节的字符串OK将在文本段中,这是一个只读数据。你也不能修改。例如ptr[0] = 'T',在这种情况下是不可能的。文本段中的字符串文字(3 个字节)将存在于整个进程的生命周期中。但是一旦控制从函数中出来func,那么分配给变量ptr以保存字符串文字地址的 4 个字节将被释放。func你也可以像下面这样编写你的函数

char* func()
{
    return "OK";
}

如下更改您的功能

char* func()
{
    char ptr[] = "OK";
    return ptr;
}

这次将为变量分配 3 个字节ptr以在本地存储字符串。此范围仅在功能范围内。

于 2012-07-14T09:50:33.817 回答
0

ptr 保存"OK"常量数据段中数据的地址。那就是返回的地址。不是ptrSo的地址即使ptr不复存在,"OK"继续存在

于 2012-07-14T05:58:18.737 回答