C语言 为什么我们不能把一个新的字符串赋给一个字符数组,而是赋给一个指针?

j91ykkif  于 11个月前  发布在  其他
关注(0)|答案(4)|浏览(144)

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

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

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

字符串
【错误】:当从类型'char'赋值给类型'char[10]'时,不兼容的类型..我搜索了这个,但找不到任何原因..我还试图通过重新声明重新赋值,如

char a[] = "Sunstroke";


但它没有工作…
但在指针的情况下,它是可能的,如在上述程序。

ibps3vxo

ibps3vxo1#

要理解这里发生的事情,两个语言规则很重要:

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

同样重要的是要理解什么是像"Sunstroke"这样的 string literal。它是一个常量字符的静态数组,足够大,可以容纳一个字符串的所有字符,结尾有一个终止符。所以在这个例子中,它是一个const char[10]数组,包含9个字符,后跟一个零值终止符。作为 static,数组在程序的生命周期内存储在存储器中的某个地方。

char a[] = "Sunstroke";

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

char *b = "Coldwave";


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

a = "Coldwave";


这试图重新分配数组,但失败了,因为数组是不可分配的。没有特别好的理由为什么它们不是;这只是语言进化的方式。

b = "Sunstroke";


这将重新分配指针指向不同的文字。这很好(除了上面提到的缺少const)。
如果你需要操作字符串,那么:

  • 在C中,你需要小心地创建足够大的数组,并使用<string.h>中的库函数(或你自己手工编写的代码)来操作这些数组中的字符;
  • 在C++中,使用std::string类为您处理内存管理,分配等。
sbtkgmzw

sbtkgmzw2#

硬编码的字符串字面量,如“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[]--不好;只能反过来做。

a14dhokn

a14dhokn3#

C 的情况下,如果我们看c99 draft standard部分6.5.16 * 赋值运算符 * 段落 2 说:
赋值运算符必须有一个可修改的左值作为其左操作数。
6.3.2.1节 * 左值、数组和函数指示符 * 第1段 * 说:
[...]可修改的左值是没有数组类型[...]的左值
因此,由于数组是不可修改的左值,所以你不能给它们赋值。至于初始化部分6.7.8 * paragraph 14 说:
字符类型的数组可以由字符串字面量[...]初始化。
C++ draft standard中,相关的部分是4.2 * 数组到指针转换 * 段落 1,内容如下:
类型为“array of N T”或“array of unknown bound of T”的左值或右值可以转换为类型为“pointer to T”的纯右值。结果是指向数组第一个元素的指针。
a prvalue是纯右值,而section 5.17 * 赋值和复合赋值运算符 * paragraph *1 * 表示:
[...]都需要一个可修改的左值作为它们的左操作数[...]

ktecyv1j

ktecyv1j4#

让我们将程序简化为:

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的值以指向其他位置。

相关问题