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

时间:2017-01-29 15:37:17

标签: c pointers

char str1[ ] = "Hello" ; 
char str2[10] ; 
char *s = "Hey" ; 
char *q ;
str2 = str1 ; /* error */ 
q = s ; /* works */ 

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

2 个答案:

答案 0 :(得分:7)

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

  1. 因为C的设计师害怕效率太低。
  2. 因为根据C的规则,如果你试图说“array1 = array2”,它实际上最终会成为“array1 =指向数组2的指针”,这就更没意义了。
  3. 现在,对这两点进行更多解释。

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

    memcpy(array1, array2, sizeof(array2));
    

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

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

    int a[10];
    int *p;
    
    p = a;
    

    作业“p = a”不是类型不匹配,它与您编写的内容完全相同

    p = &a[0];
    

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

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

    int a1[10], a2[10];
    a1 = a2;             /* wrong */
    

    就好像你说过

    a1 = &a2[0];         /* also wrong */
    

    这没有任何意义。

    最后,结构怎么样?你可以将一个结构分配给另一个结构,这通常涉及复制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;
    

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

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

答案 1 :(得分:2)

它是C数组的历史属性,它以B和BCPL语言中的数组属性为根。

C阵列与B / BCPL阵列不同,特别是因为C语言引入了structs的概念,并希望使struct类型易于复制(今天你可以赋值struct类型,即使里面有数组)。但在其他方面,C阵列尽可能地模拟B / BCPL阵列。这就是使C数组通常不可复制的原因。

有关详细信息,请参阅此处:https://stackoverflow.com/a/38857777/187690