【问题标题】:Where is local pointer stored in memory?本地指针存储在内存中的什么位置?
【发布时间】:2012-07-14 04:40:14
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: c pointers


    【解决方案1】:

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

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

    char *c;
    

    然后你这样做了:

    c = func();
    

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

    让我们看看你的函数

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

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

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

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

    c = func(); 
    

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

    回答你的问题:

    • ptr 存储在 堆栈
    • 退出 func() 时 ptr 从堆栈中弹出

    【讨论】:

      【解决方案2】:

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

      局部变量ptrfunc之外不存在,所以调用者不能也不应该引用它。

      但是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;
      }
      

      这是不行的,因为现在你正在返回一个指向数组的指针,该数组是 localfunc

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

      【讨论】:

        【解决方案3】:

        当您调用函数时,它的所有局部变量和返回地址都会压入堆栈。所以 ptr 将在堆栈上,但在常量数据部分中是“OK”字符串。当你从func返回时,ptr的值被赋值给c变量,ptr不再存在(实际上存在),但它的值存储在c中。

        【讨论】:

        • C 标准不使用术语“堆栈”
        • 我同意你的看法。但我的疑问是当 func 返回时,ptr 的范围以 func 结尾。它如何仍然有效?那是我无法理解的..
        • 例如,从函数返回时,返回值可能存储在eax寄存器中。
        【解决方案4】:

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

        【讨论】:

        • C 标准不使用术语“常量数据部分”
        • 虽然确实如此,但总比不使用名称更有帮助。
        • 字符串文字是具有静态存储持续时间的字符数组类型的只读对象。编译器如何实现这个只读属性(如/在“常量数据段”、“只读数据段”或其他任何东西中)是实现定义的,因此不是主要的。
        【解决方案5】:

        如果你指的是字符串OK存储的位置,那么它存储在内存的代码部分中,ptr存储在堆栈中强>。

        并且OK 在代码部分的位置仍然可以访问,因为它的地址是由func() 返回的。

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

        const char * func ()
        

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

        【讨论】:

          【解决方案6】:

          ptr 保存常量数据部分中"OK" 数据的地址。那就是返回的地址。不是ptr 的地址所以即使ptr 不复存在,"OK" 仍然存在

          【讨论】:

            【解决方案7】:

            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;
            }
            

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

            【讨论】:

              【解决方案8】:

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

              char* func()
              {
                      char* ptr;
                      ptr = (char*)malloc(100);
                      strcpy(ptr, "OK");
                      return ptr;
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-10-17
                • 2010-11-20
                • 2021-01-17
                • 1970-01-01
                相关资源
                最近更新 更多