繁体   English   中英

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

[英]Why can´t we assign a new string to an char array, but to a pointer?

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

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

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

[错误]:从类型 'char *' 分配到类型 'char[10]' 时类型不兼容。

char a[] = "Sunstroke";

但它没有用...

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

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

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

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

诸如“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[] —— 不好; 你只能反过来做。

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

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

和第6.3.2.1左值、数组和函数指示符1段说:

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

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

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

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

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

prvalue是纯右值,第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
 ^                                                                 ^
 |                                                                 |
 a                                                                 b

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM