C - 当 char 指针设置为新地址时旧数据会发生什么?

C - What happen to old data when char pointer set to new address?

假设我们有一个简单的 char*,然后我们重新分配地址。

char* foo = "Hello"; // [Hello] is somewhere in the memory.
char* bar = "World"; // [World] is somewhere in the memory.
foo = bar; // 'foo' and 'bar' pointing to "World", What happen to "Hello"?

我知道“Hello”和“World”是静态的,但聪明的编译器是否理解并为您清理内存?

-- 编辑和信息 --

根据评论,结果似乎有两点不同,代码和编译器优化标志。

// Example 1
// Compiler Optimization Off
char* foo = "Hello";
char* bar = "World";
foo = bar; // <-- "Hello" Still on the memory.

// Example 2
// Compiler Optimization On
char* foo = "Hello"; // <-- "Hello" never exist on binary.
char* bar = "World";
foo = bar;

// Example 3
// Compiler Optimization Off
char* foo = "Hello"; // Exist on binary because it's used on the next line
printf("%s\n", foo);
char* bar = "World";
foo = bar; // Probably "hello" still exist on memory because optimization is off.

// Example 4
// Compiler Optimization On
char* foo = "Hello"; // Exist on binary because it's used on the next line
printf("%s\n", foo);
char* bar = "World";
foo = bar; // <-- What happen to "Hello" now?

你能解释示例 4吗?

谢谢。

旧数据没有任何变化。事实上,规范说什么都不应该发生。 "Hello" 在程序运行期间持续存在,即使 foo 不再指向它。

您可以通过以下程序使用 godbolt.org 编译器资源管理器查看结果:

#include <stdio.h>

int main() {
    
    char* foo = "Hello"; // [Hello] is somewhere in the memory.
    char* bar = "World"; // [World] is somewhere in the memory.
    foo = bar; // 'foo' and 'bar' pointing to "World", What happen to "Hello"?
    printf("%s\n", foo);
}

没有优化,两个字符串都在二进制文件中。

https://godbolt.org/z/77xbxbGG4

通过 -O3 优化,Hello 未放入二进制文件中。

https://godbolt.org/z/soeqjYGKo

请注意,此优化之所以可行,是因为从未实际使用过 foo 的初始值。这是一个非常不现实的例子——如果要立即重新分配它,为什么要初始化 foo

“Hello”和“World”是具有静态存储持续时间的字符串文字。即当它们出现在程序中时,编译器将它们存储为字符数组。

所以在这些声明之后

char* foo = "Hello";
char* bar = "World";

指针 foo 和 bar 指向这些字符数组的第一个字符。

这次作业后

foo = bar;

字符串文字“Hello”仍然存在,但您无法访问它。

你可以在这个作业之后写下下面的例子

foo = "Hello";

现在,根据编译器选项,编译器要么分配先前使用的字符串文字的第一个字符的地址,要么创建另一个具有静态存储持续时间的数组,其中将包含相同的字符串“Hello”。

也就是这个if语句

if ( "Hello" == "Hello" )

可以根据编译器选项评估为逻辑 true 或 false,这些编译器选项指定相同的字符串文字是存储为一个字符数组还是存储为两个不同的字符数组。

通常编译器在一个名为文字池的特殊内存范围内收集字符串文字。