为什么字符串数组不能重新分配但字符串指针可以用C语言?

kau*_*hya 1 c pointers

char str1[ ] = "Hello" ; 
char str2[10] ; 
char *s = "Hey" ; 
char *q ;
str2 = str1 ; /* error */ 
q = s ; /* works */ 
Run Code Online (Sandbox Code Playgroud)

是C中的内置财产还是存在某种原因?如果无法分配数组,为什么还要分配包含数组的结构?

Ste*_*mit 7

您无法分配数组有两个原因:

  1. 因为C的设计者害怕效率太低.
  2. 因为根据C的规则,如果你试图说"array1 = array2",它实际上最终会成为"array1 =指向数组2的指针",这就更没意义了.

现在,对这两点进行更多解释.

(1)C的原始目标之一就是它的所有内置操作都转换为一个或两个机器指令.任何复杂或昂贵的东西通常都需要一个明确的函数调用.所以,如果你想一个数组复制到另一个,必须明确地写

memcpy(array1, array2, sizeof(array2));
Run Code Online (Sandbox Code Playgroud)

编译器不愿意为您生成这个可能代价高昂的代码.(是的,我知道,结构分配与此规则相矛盾.稍后会详细介绍.)

(2)这是C的基本规则(所谓的"数组和指针之间的等价"),除了少数例外,当你在表达式中提到数组时,你会自动获得指向数组第一个元素的指针.也就是说,如果你说

int a[10];
int *p;

p = a;
Run Code Online (Sandbox Code Playgroud)

赋值" p = a"不是类型不匹配,它与您编写的内容完全相同

p = &a[0];
Run Code Online (Sandbox Code Playgroud)

也就是说,p接收指向a第一个元素的指针.

因此,如果您尝试将一个数组分配给另一个数组:

int a1[10], a2[10];
a1 = a2;             /* wrong */
Run Code Online (Sandbox Code Playgroud)

就好像你说过的那样

a1 = &a2[0];         /* also wrong */
Run Code Online (Sandbox Code Playgroud)

这没有任何意义.

最后,结构怎么样?您可以将一个结构分配给另一个结构,这通常涉及复制N个字节,这只是我声称当您键入的所有内容都是一个赋值运算符时C不愿意做的那种可能很昂贵的操作=.这确实是一个例外,一个矛盾; 它在某种程度上是C语言的内部不一致.这就是它的发展方式.

我很确定C的第一个版本(也就是Ritchie最初版本的PDP-11的C编译器)根本没有结构.然后,当首次添加结构时,它们有一个限制:您无法分配它们,或将它们传递给函数,或从函数返回它们.(这些限制使得结构变得不那么有用,但它们在保持编译器简单的背景下是有意义的,并且没有在它背后生成昂贵的代码.)然后,仍然在后面,限制被删除:struct assigning(以及传递和返回) )都添加了.(这是在很久以前的时间,在C的黎明时期.如果我没记错的话,K&R书的第一版表示限制将被"很快解除",并且编译器的一个版本支持他们出来的时候,这本书几乎在书店里出现了.)

如果你想为矛盾道歉,你可以指出结构通常很小(意味着它们通常可以只使用几条指令来分配),而数组可以任意大.但是,再次,即使你想通过添加数组赋值以某种方式扩展语言,你也不能,因为理由#2.

人们经常说数组类型是C语言中的"二等公民",这意味着你无法分配它们,或者将它们传递给函数或从函数返回.而且,这永远无法解决(它们的二级状态可能没有解放),因为已经定义了当您尝试分配数组或将其传递给函数或从函数返回时发生的情况:在所有情况下,您最终只会使用指向数组第一个元素的指针进行操作.

(我认为多年来一直尝试将数组赋值添加为扩展,使用一些特殊的语法来"关闭"指针等价规则.我不记得它们是如何工作的,但我不认为它们中的任何一个曾经流行,更不用说成为标准了.)


两个脚注:

[1]由于您可以分配结构,因此可以通过将数组包装在结构中来欺骗编译器为您执行数组赋值.例如:

struct array_as_struct { int a[10]; };
struct array_as_struct s1, s2;
s1.a[0] = 10;
s1.a[1] = 20;
s2 = s1;
Run Code Online (Sandbox Code Playgroud)

这是完全合法的; 你完全被允许逃脱这个"诡计"; 即使结构恰好包含数组,您可以分配结构的规则也是适用的.

[2]在过去,你无法将结构传递给函数的事实是库函数像asctime接受指针(以及函数localtime返回它们)的原因之一.这些功能的定义一直持续到今天.