小心“字符串数组”这个短语。“字符串”不是 C 中的数据类型;这是一个数据布局。具体来说,一个字符串被定义为
由第一个空字符终止并包括第一个空字符的连续字符序列
一个数组char
可能包含一个字符串,而一个char*
指针可能指向一个字符串(的第一个字符)。(标准将指向字符串第一个字符的指针定义为指向字符串的指针。)
char some_array_of_strings[3][200];
这定义了一个 3 元素数组,其中每个元素都是 200 个元素的数组char
。(这是一个二维数组,在 C 中只是一个数组数组。)
strcpy(some_array_of_strings[2], "Some garbage");
字符串字面"Some garbage"
量是指匿名静态分配的数组char
;它存在于你的程序的整个执行过程中,你不能修改它。strcpy()
顾名思义,该调用将该数组的内容复制'\0'
到some_array_of_strings[]
.
strcpy(some_array_of_strings[2], "Some other garbage");
同样的事情:这会将内容复制"Some other garbage"
到some_array_of_strings[2]
中,覆盖您在上一行复制的内容。在这两种情况下,都有足够的空间。
您不是在修改字符串文字,而是通过从字符串文字(更准确地说,从我上面提到的匿名数组)复制字节来修改自己的数组。
some_array_of_strings[1]="Some garbage";
这不仅“不起作用”,而且是非法的。C中没有数组的赋值。
让我们举一个更简单的例子:
char arr[10];
arr = "hello"; /* also illegal */
arr
是数组类型的对象。在大多数情况下,数组类型的表达式被隐式转换为指向数组对象第一个元素的指针。这适用于赋值的双方:对象名称arr
和字符串字面量"hello"
。
但是左边的指针只是一个指针值。没有指针对象。用技术术语来说,它不是左值,所以它不能出现在作业的左侧,就像你写的一样42 = x;
)。
(如果数组到指针的转换没有发生,它仍然是非法的,因为 C 不允许数组赋值。)
关于赋值左侧数组问题的更多细节:
数组表达式不衰减为指针的上下文是当数组表达式为:
- 一元运算
sizeof
符的操作数;
- 一元
&
(地址)运算符的操作数;或者
- 用于初始化数组对象的初始化程序中的字符串文字。
赋值的左侧不是这些上下文中的任何一个,所以在:
char array[10];
array = "hello";
LHS 原则上被转换为指针。但是生成的指针表达式不再是左值,这使得赋值违反了约束。
一种看待它的方法是将表达式array
转换为指针,然后使赋值非法。另一个是由于赋值是非法的,整个程序不是有效的 C,所以它没有定义的行为,询问是否发生任何转换是没有意义的。
(我对“非法”这个词的使用有点快和松散,但这个答案已经足够长了,所以我不会进入它。)
推荐阅读: comp.lang.c FAQ的第 6 节;它很好地解释了 C 中数组和指针之间经常令人困惑的关系。