这有效:
int main()
{
char *t = "Hello";
t = "World";
printf("%s", t);
}
但这会产生分段错误:
int main()
{
char *t = "Hello";
strcpy(t, "World"); // the only difference
printf("%s", t);
}
为什么?
您明确定义的字符串 - 例如"Hello"
- 通常放置在只读内存区域中。这些字符串不能更改。
在第一个示例中,您没有将“Hello”字符串更改为“World”字符串。您正在重新分配t
,使其指向“World”而不是“Hello”。“Hello”字符串仍然在只读存储器中徘徊,未受影响。
这是初始状态:
t -> "Hello"
"World"
这是第二种状态:
"Hello"
t -> "World"
在第二个示例中,您试图覆盖“Hello”字符串。这是无法做到的。
您真的应该将您的声明从 更改char *t
为const char *t
。我认为 GCC 可以配置为强制执行此操作。
在第一个例子中,指针t
指向一个字符串常量"Hello"
,然后立即指向字符串常量"World"
;然后打印后一个值。
第二个示例中的代码因段错误而崩溃,因为字符串常量不可写。(strcpy 尝试修改保存文本的内存"Hello"
)。GCC 将字符串常量放入只读部分,除非使用-fwriteable-strings
.
编码
char *test = "Hello";
意味着编译器+链接器将一串字节“Hello\0”放在只读部分中,并将test
点指向其中的第一个字符。任何通过此指针写入的尝试都将受到操作系统的严厉惩罚。
另一方面
char test[] = "Hello";
声明一个 6 个字符的数组,初始值为 ( { 'H', 'e', 'l', 'l', 'o', '\0' }
)。
一些旧程序假定字符串常量是可写的;因此需要 GCC 支持使用-fwriteable-strings
命令行开关编译这些程序。
第一个将 的值t
从 的地址更改"Hello"
为 的地址"World"
。第二个尝试覆盖数据"Hello"
本身。
赋值t = "World"
只改变指针,而strcpy
改变 t 指向的内存。字符串文字可能存在于只读段中。
char* t
是一个指针。在第一个示例中,您只是将指针从一个字符串文字分配给另一个:首先t
指向"Hello"
,然后指向"World"
。这是完全合法的。
但是,字符串文字本身就是文字——它们不能更改。通常它们位于内存的只读部分中。在第二个示例中,您试图"Hello"
通过用 覆盖它来更改分配给字符串文字的内存中的内容"World"
。这是非法的,你会得到一个分段错误。
在char *t="Hello"
t
只读位置分配“Hello”。因此写入只读位置会导致分段错误。
分配和复制是有区别的。
第一个示例,您尝试将另一个字符串的地址分配给t
.
在第二个示例中,您尝试写入只读位置。
使用 char t[] = "Hello"
。这里 t 可以被覆盖
更多解释在这里
“Hello”是一个字符串常量。根据constant的定义,它并不意味着要写在上面。
在您的第一个示例中,'t' 是一个指针,它可以指向(分配)任一字符串常量。