如果char*s是只读的,为什么我可以覆盖它们?

sal*_*000 14 c arrays string string-literals

我的课程告诉我,char*s是静态的/只读的,所以我认为这意味着你在定义之后就无法编辑它们.但是当我跑步时:

char* fruit = "banana";
printf("fruit is %s\n", fruit);
fruit = "apple";
printf("fruit is %s\n", fruit);
Run Code Online (Sandbox Code Playgroud)

然后编译好并给我:

fruit is banana
fruit is apple
Run Code Online (Sandbox Code Playgroud)

为什么?我误解了只读是什么意思吗?很抱歉,如果这很明显,但我是新手编码,我无法在线找到答案.

Vla*_*cow 20

显示的代码段不会更改字符串文字本身.它仅更改存储在指针中的值fruit.

你可以想象这些线条

char* fruit = "banana";
fruit = "apple";
Run Code Online (Sandbox Code Playgroud)

以下方式

char unnamed_static_array_banana[] = { 'b', 'a', 'n', 'a', 'n', 'a', '\0' };
char *fruit = &unnamed_static_array_banana[0];
char unnamed_static_array_apple[]  = { 'a', 'p', 'p', 'l', 'e', '\0' };
fruit = &unnamed_static_array_apple[0];
Run Code Online (Sandbox Code Playgroud)

这些语句不会更改与字符串文字对应的数组.

另一方面,如果你试图写

char* fruit = "banana";
printf("fruit is %s\n", fruit);
fruit[0] = 'h';
^^^^^^^^^^^^^^
printf("fruit is %s\n", fruit);
Run Code Online (Sandbox Code Playgroud)

也就是说,如果您尝试使用指向它的指针(对于字符串文字的第一个字符)更改字符串文字,则程序具有未定义的行为.

来自C标准(6.4.5字符串文字)

7如果这些数组的元素具有适当的值,则这些数组是否不同是未指定的.如果程序试图修改此类数组,则行为未定义.

  • @sally2000: **NO** 如果你有一个数组,`fruit` 不是一个指针——它是一个数组。现在确实,如果您使用数组的名称,它将衰减为指向 char 的指针,但它*是*一个数组。例如,如果你写 `char Fruit [10] = {'a','p','p','l','e','\0'};` 你就不能写 `fruit = "香蕉”;`。你还会发现 `sizeof(fruit);` 是 10,而不是 `sizeof(char*)`(可能是 4 或 8)。 (2认同)

Kaz*_*Kaz 8

在程序中,表达式"banana"表示程序映像中的字符串文字对象,即字符数组.表达式的值是类型char *,或"指向字符的指针".指针指向该数组的第一个字节,即字符'b'.

您的char *fruit变量还具有"指向字符的指针"类型,并从该表达式中获取其初始值:它被初始化为指向数据的指针的副本,而不是数据本身; 它只是指向了b.

当你赋值"apple"fruit,你只是用另一个指针值替换它的指针值,所以它现在指向一个不同的文字数组.

要修改数据本身,您需要一个表达式,例如:

char *fruit = "banana";
fruit[0] = 'z';  /* try to turn "banana" into "zanana" */
Run Code Online (Sandbox Code Playgroud)

根据ISO C标准,没有定义其行为.这可能是该"banana"阵列是只读的,但不是必需的.

C实现可以使字符串文字可写,或使其成为一个选项.

(如果你能够修改一个字符串文字,那并不意味着一切都很好.首先,你的程序仍然没有根据ISO C定义:它不可移植.其次,允许C编译器合并文字在同一个存储器中有共同的内容.这意味着程序中两次出现的"banana"事实上可能是完全相同的数组.此外,"nana"程序中某处出现的字符串文字可能是"banana"其他地方出现的数组的后缀;换句话说,共享相同的存储.修改文字可以产生令人惊讶的效果;修改可以出现在其他文字中.)

"静态"和"只读"也不是同义词.C中的大多数静态存储实际上是可修改的.我们可以创建一个可修改的静态字符数组,它包含如下字符串:

/* at file scope, i.e. outside of any function */
char fruit[] = "banana";
Run Code Online (Sandbox Code Playgroud)

要么:

{
  /* in a function */
  static fruit[] = "banana";
Run Code Online (Sandbox Code Playgroud)

如果我们省略数组大小,它将从初始化字符串文字自动调整大小,并包含空终止字节的空间.在函数中,我们需要static将数组放入静态存储,否则我们得到一个局部变量.

这些数组可以修改; fruit[0] = 'z'是明确定义的行为.

此外,在这些情况下,"banana"不表示字符数组.数组是变量fruit; 的"banana"表达只是一块语法指示数组的初始值:

char *fruit = "banana";  // "banana" is an object in program image
                         // initial value is a pointer to that object

char fruit_array[] = "apple"; // "apple" is syntax giving initial value
Run Code Online (Sandbox Code Playgroud)


Joh*_*ode 5

fruit对象是可写的 - 它可以设置为指向不同的字符串文字。

字符串文字 "banana""apple"不可写。您可以修改fruit以指向字符串文字,但如果这样做,则不应尝试修改fruit 指向的内容

char *fruit = "banana"; // fruit points to first character of string literal
fruit = "apple";        // okay, fruit points to first character of different string literal
*fruit = 'A';           // not okay, attempting to modify contents of string literal
fruit[1] = 'P';         // not okay, attempting to modify contents of string literal
Run Code Online (Sandbox Code Playgroud)

尝试修改字符串文字的内容会导致未定义的行为 - 您的代码可能按预期工作,或者您可能会遇到运行时错误,或者可能发生完全意外的事情。为安全起见,如果您定义一个指向字符串文字的变量,您应该声明它const

const char *fruit = "banana";  // can also be written char const *
Run Code Online (Sandbox Code Playgroud)

您仍然可以分配fruit指向不同的字符串:

fruit = "apple";
Run Code Online (Sandbox Code Playgroud)

但是如果你试图修改fruit指向的内容,编译器会骂你。

如果你想定义一个只能指向一个特定字符串文字const的指针,那么你也可以-qualify 指针:

const char * const fruit = "banana"; // can also be written char const * const
Run Code Online (Sandbox Code Playgroud)

这样,如果您尝试写入指向的内容fruit,或尝试设置fruit指向不同的对象,编译器就会对您大喊大叫。