#include <stdio.h>
int main() {
char *t = "hello world";
puts(t);
//printf("%s", t);
t = "goodbye world";
puts(t);
}
t 的内存没有分配,那么为什么我在运行它时没有出现段错误?
#include <stdio.h>
int main() {
char *t = "hello world";
puts(t);
//printf("%s", t);
t = "goodbye world";
puts(t);
}
t 的内存没有分配,那么为什么我在运行它时没有出现段错误?
t 是一个指针,所以你只是让 t 指向另一个字符串。
因为字符串文字是在程序内存中静态分配的 - 您不需要显式地为它们分配内存。
内存分配给; t
为其分配了足够的内存来保存指针(通常,在 32 位程序中为 4 个字节,在 64 位程序中为 8 个字节)。
此外,初始化t
确保指针指向某处:
char *t = "hello world";
字符串文字也在某处分配了空间。通常,这是在内存的只读部分,所以你真的应该使用const char *t = "hello world";
,即使你不使用显式const
,你也不应该尝试修改t
指向的字符串。但是编译器的问题是确保t
指向有效的地方。
同样,赋值后:
t = "goodbye, Cruel World!";
该变量指向编译器分配的空间。只要您不滥用它(并且您的代码没有),这很好。
会让你陷入麻烦的是这样的事情:
char *t;
puts(t); // t is uninitialized; undefined behaviour
t = 0; // equivalently, t = NULL;
puts(t); // t contains the null pointer; undefined behaviour
未初始化的局部变量可以包含任何值;你无法可靠地预测会发生什么。在某些机器上,它可能包含空指针并导致崩溃,但这不是您可以依赖的。
空指针不指向任何有效的东西,因此取消引用空指针会导致未定义的行为,而且这种未定义的行为通常会导致崩溃。(经典地,在 DEC VAX 机器上,您在地址零处得到一个零字节而不是崩溃。这(部分)导致亨利斯宾塞的 十诫之一“全世界都不是 VAX”——以及“你不应该跟随 NULL 指针,因为混乱和疯狂在它的尽头等待着你。”)
因此,在您的程序中,内存被分配t
并t
初始化并分配为指向(只读)字符串常量,因此程序没有任何借口崩溃。
编译器需要分配的所有内存t
是 32 位系统上的 4 个字节。请记住,它只是一个指针。在前几行中,它指向“hello world”,但之后您将其更改为指向“goodbye world”。C 将为您定义的字符串分配足够的内存并将指针传递给您,以便您可以指向它们。你不必担心这一点。还要记住,这些字符串是静态的和只读的,这意味着你不能安全地说t[4] = 'b';
.