在作用域中创建指针时,当指针超出作用域时,指向的变量会发生什么情况

When a pointer is created in scope, what happens to the pointed to variable when the pointer goes out of scope?

本文关键字:指针 作用域 变量 什么情况 创建      更新时间:2023-10-16

标题说明了一切。

我发现了一个本质上相同的老问题,但我需要进一步澄清。

在这个问题中,接受的答案是:

char* text = "Hello, world"; 

这里的自动变量(指针(是 在堆栈上创建并设置为指向常量内存中的值, 这意味着:

  • " 中的字符串文本在整个程序执行过程中存在。
  • 您不负责"分配"或"释放"它
  • 你可能不会 改变它。如果你想改变它,那么你必须分配一些 "非常量内存"并将其复制到那里。

这是否意味着指针被删除,但指针指向的数据没有被删除?如果我在一个函数中创建 1,000,000 个指向字符的指针,当它们超出范围时,我的所有内存都会被释放吗?或者只是制作指针所需的内存,留下实际角色本身来占用我所有的记忆?

字符

数组将在整个程序执行过程中闲逛,因为它们具有静态存储持续时间。这并不意味着您需要删除它们 - 它们应该在整个程序期间保留。事实上,调用delete它会给你不确定的行为。您只能delete分配了new .

指针本身具有自动存储持续时间,并在超出范围时销毁。值得注意的是,指针必须是const char*,因为字符串文字为您提供了一个const char数组。考虑:

void func()
{
  const char* str = "Hello";
}

包含Hello字符数组在程序运行期间存在。指针str仅在该函数的持续时间内存在。这里不需要deleted任何东西。

如果你仔细想想,这很有意义。您在源代码中编写的所有这些字符串都必须存在于可执行文件中的某个位置。编译器通常将这些字符串写入可执行文件的数据。运行程序时,可执行文件将与包含字符串的数据段一起加载到内存中。

如果程序中有两个字符串文本具有相同或重叠的文本,则编译器没有理由不能将其优化为仅存储其中一个。考虑:

void func()
{
  const char* str1 = "Hello";
  const char* str2 = "Hello";
  const char* str3 = "lo";
}

编译器只需要在此处将Hello字符写入可执行文件一次。前两个指针将仅指向H,第三个指针将指向第二个l。编译器可以进行这样的优化。当然,通过这个例子,编译器可以通过一起删除字符串来进行进一步的优化 - 它们不会以任何有助于程序可观察行为的方式使用。

所以是的,如果你有一百万个不同的字符串文字,以某种方式有助于程序的可观察行为,当然它们必须作为可执行文件的一部分存在。

我会说"什么都没有"(回答标题(,如果SO认为这是一个答案就足够了。

至于你的百万

个指向字符的指针,虽然指针会被弹出(尽管你必须有相当多的堆栈来容纳百万个指针(,但它们指向的数据将困扰你的记忆。

不幸的是,您的示例不足以解决全貌。

首先,一些简单的临时词汇和解释:记忆单元是一个(输入C++(具有给定大小的内存区域,它包含一个。多个存储单元可能包含相同的值,这无关紧要。

您应该考虑 3 种类型的存储单元

  • "Hello, World!" :此存储单元具有静态存储持续时间,它存在于整个程序期间
  • void foo(int a);void foo() { int a = 5; }:在这两种情况下,存储单元a都具有自动存储持续时间,一旦功能foo返回,它就会自动消失
  • void foo() { int* a = new 5; }:在"某处"创建一个匿名存储单元来存储值5,并创建一个具有自动存储持续时间a的存储单元来存储匿名存储单元的地址

那么,当指针超出范围(消失(时会发生什么?

嗯,就是这样。指针消失。最具体地说,它所指向的存储单元没有任何特殊变化。

void foo(int a) {
    int* pointer = &a;
} // pointer disappears, `a` still exists briefly
void foo() {
    int* pointer = 0;
    {
        int a;
        pointer = &a;
    } // a disappears, pointer's value does not change...
} // pointer disappears

事实上,在 C 和 C++ 中:

  • 您可以保留不再存在的对象的地址 =>悬空引用
  • 您可能会丢失现有对象的所有地址 => 内存泄漏

那么,当char const* text = "Hello, world";中的text超出范围时会发生什么?

无。

指针本身占用"自动存储"(通常是堆栈(上的空间。一旦函数返回[或范围完成,但从技术上讲,几乎所有编译器都会"等待"到函数返回后再释放空间]。

如果在循环中调用同一函数 100 万次,则在任何给定时间都只有一个指针。如果您有 100 万个函数 [和大量内存],则当前调用的每个函数都有一个指针。例如

char *foo()
{
    char *text1 = "Hello";
    return text1;
}
void bar()
{
    char *text2 = "World!";
    printf("%s %s!n", foo(), text2);
}

void baz()
{
    char *text3 = "Meh";
    bar();
}
int main()
{
    char *text4 = "Main";
    baz();
}

当我们输入 main 时,text4 在堆栈上创建 - 它被初始化为字符串"Main",该字符串保存在其他内存中。当我们调用 baz() 时,text3被创建并初始化为"Meh",它调用创建text2并指向文本"World"的bar(),并调用创建text1并启动Hellofoo。当foo返回时,text1 内部的地址作为返回值给出,指针本身消失。printf()完成后,bar返回,指针消失。

只要程序正在运行,字符串"Main","Meh","Hello"和"World"仍然保持不变。