3

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

main()
{
    char a[] = "Sunstroke";
    char *b = "Coldwave";

    a = "Coldwave";
    b = "Sunstroke";
    printf("\n %s %s",a,b);
}

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

char a[] = "Sunstroke";

但它没有用......

但在指针的情况下,可以像上面的程序一样..

4

4 回答 4

6

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

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

理解什么是字符串文字也很重要"Sunstroke"。它是一个由常量字符组成的静态数组,大到足以容纳结尾带有终止符的字符串的所有字符。所以在这种情况下,它是一个const char[10]数组,包含九个字符,后跟零值终止符。作为static,该数组在程序的生命周期内存储在内存中的某个位置。

char a[] = "Sunstroke";

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

char *b = "Coldwave";

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

a = "Coldwave";

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

b = "Sunstroke";

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

如果您需要操作字符串,则:

  • 在 C 语言中,您需要小心地创建足够大的数组以满足您的需要,并使用<string.h>(或您自己的手工代码)中的库函数来操作这些数组中的字符;
  • 在 C++ 中,使用std::string该类为您处理内存管理、分配等。
于 2013-09-11T15:51:41.697 回答
4

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

char *b = "Coldwave";

achar[]已分配给它。没关系。但它与此不同:

char a[] = "Coldwave";

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

char c[] = a;

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

因此,您不能使用上面的变量执行此操作的原因:

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

是因为那会将 a 分配char*给 a char[]-- 不好;你只能反过来做。

于 2013-09-11T15:39:53.873 回答
3

C的情况下,如果我们查看c99 草案标准部分6.5.16 赋值运算符2段说:

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

和部分6.3.2.1 Lvalues, arrays, and function designators1段说:

[...]可修改的左值是没有数组类型的左值[...]

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

字符类型的数组可以由字符串字面量初始化[...]

C++ 草案标准中,相关部分是4.2 Array-to-pointer conversion1段,其中说:

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

prvalue是纯右值和部分5.17 赋值和复合赋值运算符1段,其中说:

[...]都需要一个可修改的左值作为它们的左操作数[...]

于 2013-09-11T15:46:42.110 回答
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
 ^                                                                 ^
 |                                                                 |
 a                                                                 b

只要数组的生命周期,a永远都是同一个地方,不能修改。

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

于 2013-09-11T15:48:10.247 回答