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

时间:2013-09-11 15:30:56

标签: c arrays pointers

我试图将一个字符串重新分配给预先初始化的数组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 个答案:

答案 0 :(得分:4)

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

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

了解"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类为您处理内存管理,分配等。

答案 1 :(得分:3)

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

char *b = "Coldwave";

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

char a[] = "Coldwave";

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

char c[] = a;

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

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

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

是因为那会将char*分配给char[] - 没有好处;你只能这样做。

答案 2 :(得分:3)

对于 C ,如果我们查看c99 draft standard部分6.5.16 分配运算符 2 说:

  

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

和部分6.3.2.1 Lvalues,数组和函数指示符 1 表示:

  

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

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

  

字符类型数组可以用字符串文字[...]

初始化

C++ draft standard中,相关部分为4.2 数组到指针转换 1 ,其中包含:

  

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

prvalue是一个纯正的左值和部分5.17 分配和复合赋值运算符段落 1 ,其中包含:

  

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

答案 3 :(得分: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的值以指向其他位置。< / p>