为什么C语言不能直接分配数组,但可以在结构体中分配数组?

8

这段代码不起作用:

int main() {
    int arr1[10];
    int arr2[10];

    arr2 = arr1;
    return 0;
}

但是这个可以工作:
struct foo {
    int arr[10];
};

int main() {
    struct foo f1;
    struct foo f2;

    f2 = f1;
    return 0;
}

但是在我看来,它们做的事情是相同的:只是将一个数组复制到另一个数组中。


4
主要是“古代历史”——指C语言还不支持结构体赋值的时期。主要问题在于数组的行为和数组名字会变成指针,这使得一般情况下处理数组赋值变得困难。传递给函数的数组在被调用的函数中没有可用的大小信息等。 - Jonathan Leffler
可能是在C语言中无法返回数组的含义是什么?的重复问题。 - Steve Summit
2个回答

5
C语言的历史发展导致了直接引用数组是不可能的。在arr2 = arr1;中,arr2arr1都指代了一个数组。但是C遵循一个规则,即当数组用于表达式时,它会自动转换为指向其第一个元素的指针,有一些例外情况。C当然能够将一个数组复制到另一个数组中,就像使用memcpy(arr2, arr1, sizeof arr2);一样。问题在于没有办法在赋值语句中引用整个数组。这种数组的自动转换是为了方便访问数组元素并以C语言最初开发时使用的方式处理数组而设计的。人们没有预料到需要将整个数组作为一个整体对象进行引用,并且没有在语言中构建任何东西来实现这一点。(即使在今天,也没有必要-除了复制之外,我们很少需要对数组执行作为单个对象的操作。)早期的C实现也不允许通过赋值来复制结构。C是一种相当基本的语言,只提供简单的操作,复制整个结构将是一件高级的事情。后来,添加了复制结构的功能。在f2 = f1;中,f2f1指代的是结构,并且没有关于它们自动转换为任何内容的规则,如数组的情况。因此,问题只是表达所需操作的问题。

1
这里
int main() {
    int arr1[10];
    int arr2[10];

    arr2 = arr1;
    return 0;
}

arr2 = arr1; 不起作用,因为arr2是数组,而数组名本身是基地址即const &,您无法更改该地址,即arr2不能指向任何其他地址。通过执行arr2 = arr1;,您正在尝试更改arr2的基地址,这是不可能的。在这里

f2 = f1; /* structure member copy, f2 is structure variable and it can assigned with another structure variable f1 */

f2是一个结构体变量,通过执行f2 = f1;f1成员将被复制到f2中。

但在我看来,它们做的事情是一样的:只是将一个数组复制到另一个数组中。

是的,但编译器不允许执行第一个arr2 = arr1,因为您不能更改arr2的基地址,而在另一个f2=f1中,f1结构体变量的成员逐个复制到f2成员中,由于f2不是一个数组,所以这是可能的

6.3.2.1 左值、数组和函数设计器中的段落

  1. 当一个对象被称为具有特定类型时,其类型是由用于指定该对象的左值指定的。*可修改的左值是一个左值,它没有数组类型没有不完整的类型,没有const限定类型,而且如果它是一个结构体或联合体,则不具有任何具有const限定类型的成员(包括递归地包含的所有聚合体或联合体的成员或元素)。

这里

arr2 = arr1;

lvalue操作数arr2不可修改的

另一个关于相同问题的段落,讲述了衰减。

  1. 除非它是sizeof运算符、_Alignof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串字面量,否则具有类型''类型的数组''的表达式将转换为具有类型''指向类型的指针''的表达式,该指针指向数组对象的初始元素,并且不是lvalue

1
“数组名称本身的地址”是错误的。(事实上,任何涉及“名称”的解释都是错误的。) - melpomene

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接