在C语言中,可以在这样的声明中使用字符串字面值:

char s[] = "hello";

或者像这样:

char *s = "hello";

那么有什么不同呢?我想知道在编译和运行时,在存储持续时间方面实际发生了什么。


当前回答

给出声明

char *s0 = "hello world";
char s1[] = "hello world";

假设下面的内存映射(列表示从给定行地址偏移0到3的字符,例如右下角的0x00在地址0x0001000C + 3 = 0x0001000F):

                     +0    +1    +2    +3
        0x00008000: 'h'   'e'   'l'   'l'
        0x00008004: 'o'   ' '   'w'   'o'
        0x00008008: 'r'   'l'   'd'   0x00
        ...
s0:     0x00010000: 0x00  0x00  0x80  0x00
s1:     0x00010004: 'h'   'e'   'l'   'l'
        0x00010008: 'o'   ' '   'w'   'o'
        0x0001000C: 'r'   'l'   'd'   0x00

字符串字面值"hello world"是一个12元素的char数组(c++中的const char),具有静态存储持续时间,这意味着它的内存在程序启动时分配,并一直分配到程序结束。试图修改字符串文字的内容会调用未定义的行为。

这条线

char *s0 = "hello world";

将s0定义为指向具有自动存储持续时间的char的指针(意味着变量s0仅存在于声明它的作用域),并将字符串字面值的地址(本例中为0x00008000)复制到它。注意,由于s0指向一个字符串字面值,它不应该被用作任何试图修改它的函数的参数(例如,strtok(), strcat(), strcpy()等)。

这条线

char s1[] = "hello world";

将s1定义为具有自动存储持续时间的12元素char数组(长度取自字符串字面量),并将字面量的内容复制到数组中。正如你从内存映射中看到的,我们有两个字符串"hello world"的副本;不同之处在于,您可以修改s1中包含的字符串。

S0和s1在大多数情况下是可以互换的;以下是例外情况:

sizeof s0 == sizeof (char*)
sizeof s1 == 12

type of &s0 == char **
type of &s1 == char (*)[12] // pointer to a 12-element array of char

您可以重新分配变量s0以指向不同的字符串字面值或另一个变量。不能将变量s1重新赋值以指向不同的数组。

其他回答

char s[] = "Hello world";

这里,s是一个字符数组,如果我们愿意,它可以被覆盖。

char *s = "hello";

字符串字面值用于在内存中的某个地方创建这些字符块。我们可以通过改变它所指向的对象来重新赋值,但只要它指向一个字符串字面值,它所指向的字符块就不能被改变。

在下列情况下:

char *x = "fred";

X是左值,它可以被赋值给。但在这种情况下:

char x[] = "fred";

X不是一个左值,它是一个右值——你不能给它赋值。

char *str = "Hello";

上面设置str指向“Hello”字面值,该字面值是硬编码在程序的二进制图像中,在内存中被标记为只读,这意味着这个String字面值的任何更改都是非法的,并且会抛出分割错误。

char str[] = "Hello";

将字符串复制到堆栈上新分配的内存中。因此,对它进行任何更改都是允许的和合法的。

means str[0] = 'M';

将str更改为“Mello”。

如欲了解更多详情,请浏览类似问题:

为什么我得到一个分割错误时写入一个字符串初始化“char *s”而不是“char s[]”?

根据这里的注释,应该很明显:char * s = "hello"; 是一个坏主意,应该在非常狭窄的范围内使用。

这可能是指出“const正确性”是一件“好事”的好机会。无论何时何地,你可以使用“const”关键字来保护你的代码,不受“宽松”的调用者或程序员的影响,当指针开始发挥作用时,它们通常是最“宽松”的。

这就是用“const”修饰指针所能达到的效果。 (注意:必须从右向左阅读指针声明。) 以下是在使用指针时保护自己的3种不同方法:

const DBJ* p means "p points to a DBJ that is const" 

-也就是说,DBJ对象不能通过p改变。

DBJ* const p means "p is a const pointer to a DBJ" 

-也就是说,你可以通过p改变DBJ对象,但你不能改变指针p本身。

const DBJ* const p means "p is a const pointer to a const DBJ" 

-也就是说,你不能改变指针p本身,也不能通过p改变DBJ对象。

与尝试常量突变相关的错误在编译时被捕获。const没有运行时空间或速度损失。

(当然,假设你使用的是c++编译器?)

——日本

补充一点:它们的大小也会有不同的值。

printf("sizeof s[] = %zu\n", sizeof(s));  //6
printf("sizeof *s  = %zu\n", sizeof(s));  //4 or 8

如上所述,对于数组'\0'将被分配为最后一个元素。