为什么第一个版本会使程序崩溃,而第二个版本不会?它们不是一回事吗?
指针表示法
char *shift = "mondo";
shift[3] = shift[2];
数组表示法
char shift[] = {'m', 'o', 'n', 'd', 'o', ' '};
shift[3] = shift[2];
兆威
int main( void )
{
char *shift = "mondo";
shift[3] = shift[2];
char shift[] = {'m', 'o', 'n', 'd', 'o', ' '};
shift[3] = shift[2];
return 0;
}
不!这是 C 语言中的重要问题之一。首先,你创建一个指向内存只读部分的指针,即你不能改变它,只能读取它。第二个,创建一个字符数组,即连续字符的内存的一部分,您可以在其中具有读取和写入访问权限,这意味着您可以读取和更改数组的值。
第一个指向字符串文字(通常在代码的只读部分中,应该确实const char *
但由于历史原因能够侥幸逃脱)|。
第二个创建一个数组,然后填充该数组。
因此它们不一样
第一个是在 中分配内存。文本段,而第二个将其放入 .BSS。 内存在 .文本段实际上是只读的或const
:
char *string = "AAAA";
这将创建有效的const char *
,因为内存将在 .文本段作为字符串文本。 由于这通常会标记为只读,因此尝试写入它将生成访问冲突或分段错误。
您要执行此操作:
char string[] = "AAAA";
这将按预期工作,并为四个大写的 As 字符串分配内存,并使用变量 string
作为指向该位置的指针。
这将创建一个指向现有字符串的指针:
char *shift = "mondo";
这将创建一个新的字符数组:
char shift[] = {'m', 'o', 'n', 'd', 'o', ' '};
在第二种情况下,您可以修改字符,因为它们是您刚刚创建的字符。
在第一种情况下,您只是指向一个永远不应修改的现有字符串。 字符串存储位置的详细信息取决于特定的编译器。 例如,它可以将字符串存储在不可修改的内存中。 编译器还可以执行一些技巧以节省空间。 例如:
char *s1 = "hello there";
char *s2 = "there";
s2
实际上可能指向位于s1
指向的字符串第七个位置的同一字母"t"。
为避免混淆,最好将 const 指针与字符串文字一起使用:
const char *shift = "mondo";
这样,编译器会在您不小心尝试修改它时通知您。
每当使用 char * str = "hello";
这是编译器隐式表达的 const char * str= "hello";
这使得此符号转到程序存储器的只读位置。
但在数组的情况下,相同的解释为 char const *array[];
这就是为什么当用户尝试更改数组的基址时编译器会尖叫的原因。这是编译器隐式完成