为什么我们不能将新字符串分配给数组,而是分配给指针

我试图将一个字符串重新分配给预先初始化的数组a [],而我所能得到的只是一个错误

main() { char a[] = "Sunstroke"; char *b = "Coldwave"; a = "Coldwave"; b = "Sunstroke"; printf("\n %s %s",a,b); } 

[错误]:从类型’char *’分配类型’char [10]’时不兼容的类型..我搜索了这个但是找不到任何原因..我也尝试通过重新声明重新分配它

 char a[] = "Sunstroke"; 

但它没有奏效……

但是在指针的情况下,有可能像上面的程序..

硬编码的字符串文字,例如“Coldwave”实际上是char[] (字符数组)类型 – 但是修改它们是未定义的行为 ( C99 :6.4.5.6)。 但是请注意,在下面, b仍然是char* (char指针):

 char *b = "Coldwave"; 

已为其分配了char[] 。 没关系。 但它与此不同:

 char a[] = "Coldwave"; 

这是char[]初始化 。 在声明变量时,您只能初始化一次变量,并且初始化是唯一可以通过这样的赋值填充数组或其他复合类型(例如结构)的情况。 但是,你无法做到这一点:

 char c[] = a; 

因为当在赋值的右侧使用时,数组变量作为它们所代表的数组的指针,这就是char *b = a原因。

所以你不能用上面的变量做到这一点:

 a = b; // or a = "Sunstroke"; 

是因为那会将char*分配给char[] – 没有好处; 你只能以相反的方式做到这一点。

要了解这里发生了什么,两个语言规则很重要:

  • 数组不可分配。
  • 可以将数组转换为指向其第一个元素的指针。

理解像"Sunstroke"这样的字符串文字也很重要。 它是一个常量字符的静态数组,大小足以容纳字符串的所有字符,并在末尾添加终止符。 所以在这种情况下,它是一个const char[10]数组,包含九个字符,后跟零值终结符。 作为静态 ,数组存储在内存中的某个地方,用于程序的生命周期。

 char a[] = "Sunstroke"; 

这将创建一个本地数组,并通过从字符串文字中复制字符来初始化它。

 char *b = "Coldwave"; 

这会创建一个指针,并将其初始化为指向文字本身。 请注意,这很危险:文字是const ,但指针不是,因此您可以编写尝试修改文字的代码,从而提供未定义的行为。 不推荐使用此转换(当然在C ++中,我不确定C),因此编译器应该给出警告。 你已经启用了所有编译器警告,不是吗?

 a = "Coldwave"; 

这会尝试重新分配数组,但由于数组不可分配而失败。 他们不是没有特别好的理由; 这就是语言演变的方式。

 b = "Sunstroke"; 

这会将指针重新指定为指向不同的文字。 这很好(除了上面提到的缺乏const )。

如果你需要操纵字符串,那么:

  • 在C语言中,您需要仔细创建足够大的数组以满足您的需求,并使用的库函数(或您自己的手工编写的代码)来操作这些数组中的字符;
  • 在C ++中,使用std::string类为您处理内存管理,分配等。

C的情况下,如果我们看一下c99标准草案第6.5.16节。 分配操作员2段说:

赋值运算符应具有可修改的左值作为其左操作数。

6.3.2.1Lvalues,数组和函数指示符1段说:

[…]可修改的左值是一个没有数组类型的左值[…]

因此,由于数组不是可修改的左值,因此无法分配给它们。 至于初始化部分6.7.8 初始化14段说:

可以通过字符串文字初始化字符类型数组[…]

在C ++草案标准中 ,相关部分是4.2 数组到指针转换1段,其中说:

可以将“数组的NT”或“未知的T的数组”类型的左值或右值转换为“指向T的指针”的prvalue。 结果是指向数组的第一个元素的指针。

prvalue是一个纯rvalue和5.17 赋值和复合赋值运算符1段,它说:

[…]所有都需要一个可修改的左值作为他们的左操作数[…]

让我简化程序:

 char a[] = "Sunstroke"; char *b = a; 

假设a的地址是100,那么在内存中,它看起来像这样(仅说明指针的大小和字节序等可能会有所不同):

 [S] [u] [n] [s] [t] [r] [o] [k] [e] [\0] ... [0] [0] [0] [100] 100 101 102 103 104 105 106 107 108 109 200 ^ ^ | | ab 

只要数组的生命周期, a永远是同一个地方,你就无法修改它。

另一方面, b是包含数组地址的指针, 可以修改b的值以指向其他地方。