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