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如果这些数组的元素具有适当的值,则这些数组是否不同是未指定的.如果程序试图修改此类数组,则行为未定义.
在程序中,表达式"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)
该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
指向不同的对象,编译器就会对您大喊大叫。
归档时间: |
|
查看次数: |
2735 次 |
最近记录: |