7

标题说明了一切。

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

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

char* text = "Hello, world"; 

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

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

这是说指针被删除,而不是指针指向的数据吗?如果我要在函数中创建 1,000,000 个指向字符的指针,当它们超出范围时,我的所有内存都会被释放吗?或者只是制作指针所需的内存,而将实际字符本身留在后面来占用我所有的内存?

4

4 回答 4

10

字符数组将在程序的整个执行过程中一直存在,因为它们具有静态存储持续时间。这并不意味着您需要删除它们——它们应该在您的整个程序期间都存在。事实上,调用delete它会给你未定义的行为。您只能delete分配与new.

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

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

包含的字符数组在Hello\0您的程序期间存在。指针str仅在该函数的持续时间内存在。什么都不需要在deleted这里。

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

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

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

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

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

于 2013-02-13T15:49:29.113 回答
2

我会说“没什么”(回答标题),如果它足以让 SO 认为它是一个答案。

至于你的百万个字符指针,而指针会被弹出(尽管你必须有相当多的堆栈来保存百万个指针)它们指向的数据会困扰你的记忆。

于 2013-02-13T15:43:21.737 回答
2

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

首先,一些简单的即席词汇和解释:内存单元是(用 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++ 中:

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

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

没有什么。

于 2013-02-13T16:26:26.237 回答
1

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

如果你在循环中调用同一个函数 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”,它调用bar()创建text2并指向文本“World”,调用foo创建并初始化text1Hello。作为foo返回,内部的地址text1作为返回值给出,指针本身消失。当printf()完成时,bar返回,指针消失。

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

于 2013-02-13T15:52:44.723 回答