这是一个非常基本的问题,但我没有找到明确的答案。我试着理解C
中的字符串文字是如何工作的。
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *str = "Hello World!";
str = "Reassign str.";
char *str2 = "Something.";
str = strdup(str2);
free(str);
exit(EXIT_SUCCESS);
}
当我对字符串文字str = "Reassign str."
或str = strdup(str2)
执行Hello World
字符串时会发生什么?它是可执行文件的一部分,它是否超出范围,重新分配str
后是否释放了内存?
答案 0 :(得分:4)
字符串文字具有静态存储持续时间。在程序执行期间,它们不会被销毁并具有相同的地址。
在这些陈述中
str = "Reassign str.";
//...
str = strdup(str2);
指针str
只是由其他一些地址重新分配。在第一个语句中,它获取字符串文字“重新分配str”的第一个字符的地址。在第二个语句中,它获取包含str2指向的字符串文字副本的字符数组的动态分配内存的地址。
根据C标准(6.4.5字符串文字)
6在转换阶段7中,附加一个值为零的字节或代码 每个由字符串文字产生的多字节字符序列 或者文字.78)然后使用多字节字符序列 初始化一组静态存储持续时间和长度 足以包含序列。对于字符串文字, 数组元素具有char类型,并使用个体初始化 多字节字符序列的字节。
和(6.2.4对象的存储持续时间)
3对象...具有静态存储持续时间。 它的一生就是 程序的整个执行及其存储的值被初始化 程序启动前只有一次
至于字符串文字本身,你可能不会改变它们。任何更改字符串文字的尝试都会导致程序的未定义行为。
来自C标准(6.4.5字符串文字)
7未指明这些阵列是否与它们不同 元素具有适当的值。 如果程序尝试 修改这样的数组,行为是未定义的。
例如,您可能不会写
char *str = "Hello World!";
*str = 'h';
答案 1 :(得分:2)
当你这样做时
char *str = "Hello World!";
编译器为该字符串文字留出了字节strlen(str) + 1
的内存。当指针str
被重新分配时,为字符串文字"Hello World!"
分配的内存不会被销毁/释放,而是在其范围内持续存在。
答案 2 :(得分:2)
代码中的一切都正常。
char *str = "Hello World!";
好的,你声明一个char *
指向一个字符串文字。为了正确,你应该写const char *str =
,因为字符串litteral是一个不可修改的字符串(str[4] = 'u';
是不正确的)
str = "Reassign str.";
好吧指针str现在指向另一个字符串。与上述相同,它应该仍然是常量。
char *str2 = "Something.";
仍然是同一个故事
str = strdup(str2);
现在str指向malloc的字符串。这是第一次str不是const是正确的。 str[0] = 's';
在这里是正确的。
free(str);
好的,你释放strdup
分配的字符串。
exit(EXIT_SUCCESS);
您很好地将定义的值(0)返回给环境。
答案 3 :(得分:2)
好像还没有足够的答案,但我认为还有一个方面值得一提:
是的,代码中的字符串文字具有静态存储是正确的,因此在整个程序执行期间它将是 alive 。在这方面,没有任何东西可以发生(你甚至无法改变它)。从技术上讲,这通常意味着字符串是程序的 part 并放入只读的数据段。
但是,在您的情况下,优化编译器将检测到"Hello World!"
从未实际使用过,因此它将从已编译的程序中消失。这对优化工具来说是合法的,因为它不会改变程序的可观察行为。
> gcc -ostrlit strlit.c
> strings strlit | grep Hello
Hello World!
> gcc -O3 -ostrlit strlit.c
> strings strlit | grep Hello
>
答案 4 :(得分:1)
通常,静态字符串位于静态数据部分中。在这种情况下,因为你的程序没有做任何事情,我不太确定;可以优化所有静态字符串。
在实际程序中,您实际使用这些静态字符串,它们将具有固定的地址。
绝不会str = strdup(str2);
释放任何记忆。在C中,内存永远不会自行释放。
答案 5 :(得分:1)
让我们打破这个:
char *str = "Hello World!";
声明一个名为str
char *str
和也声明字符串文字
"Hello World!";
和还将str
设置为指向文字的第一个字符。
文字具有静态存储持续时间 - 它被编译到您的可执行文件中,始终存在,并且无法移动或更改。
指针只是一个指针,你可以随时指向其他东西。
答案 6 :(得分:0)
声明字符串文字时,例如:
char *str = "Hello World!";
"Hello World!"
字符串存储在内存的只读部分。所以如果你是其中之一:
str[1] = 'i';
strcpy(str, "Goodbye!");
你很可能是核心转储。另一方面,如果你这样做:
str = malloc(10);
strcpy(str, "Goodbye!");
你会没事的,虽然你会松开你对原始字符串的指针。