为什么数组赋值操作没有';C语言中不存在结构赋值,但结构赋值存在吗?

为什么数组赋值操作没有';C语言中不存在结构赋值,但结构赋值存在吗?,c,arrays,C,Arrays,[我知道a和b在第一种情况下是地址,但在第二种情况下是符号]数组名是常量指针,因此您无法更改它指向的内容 假设最后一行的c=d是合法的,它只是将一个非常量变量复制到另一个非常量变量,这是完全合法的。因为c说不能,所以它说“可修改的左值是没有数组类型的左值,不是吗?” 没有不完整的类型”,因此无法将数组分配给 而且, 在值上下文中使用数组名称时,如a=b,名称a和b都表示 &a[0]和&b[0]。通常被称为指向指针的数组“衰减” 但是,数组不是指针,因此尝试使用指针分配数组是没有意义的。a实际上是

[我知道a和b在第一种情况下是地址,但在第二种情况下是符号]

数组名是常量指针,因此您无法更改它指向的内容


假设最后一行的c=d是合法的,它只是将一个非常量变量复制到另一个非常量变量,这是完全合法的。

因为c说不能,所以它说“可修改的左值是没有数组类型的左值,不是吗?” 没有不完整的类型”,因此无法将数组分配给

而且, 在值上下文中使用数组名称时,如
a=b
,名称
a
b
都表示
&a[0]
&b[0]
。通常被称为指向指针的数组“衰减”

但是,数组不是指针,因此尝试使用指针分配数组是没有意义的。

a实际上是指向数组第一个元素的“指针”,它是一个常量“指针”, 因此,您正在尝试分配一个l-“指针”

您可以通过以下方式实现您的目标:

int a[10];
int b[10];

a = b; // illegal

typedef struct {
    int real;
    int imag;
    } complex;

complex c,d;
c = d; //legal
编辑:我忘了提到数组不应被视为指针的一些例外情况:

-可以使用sizeof(数组),但不能使用sizeof(指针)

-文本字符串数组


-a和&a是相同的,这是因为您使用的数组类型是所谓的静态数组,即它的内存在堆栈上。 如果您使用动态数组(带指针),那么您的赋值将是合法的(但内存泄漏是可能的)。这将是一个肤浅的副本


另请参见

主要原因当然是标准。在赋值运算符约束上,它表示:

(C99,6.5.16p2)“赋值运算符应具有可修改的左值作为其左操作数”

其中,它将可修改的左值定义为

(C99,6.3.2.1p1)“可修改的左值是没有数组类型[…]的左值”

因此,不允许分配给数组


但主要原因是在阵列拷贝被认为不适合硬件(旧PDP系统)的时候的历史原因。并非如此,在C的第一个版本中,结构类型对象的赋值也是不允许的。它后来被添加到语言中,但对于数组,语言的许多部分都需要更改以允许分配给数组

首先要了解的是数组不是指针。请阅读本手册第6节。我会等的

好的,做完了吗?不,回去看看整件事

太好了,谢谢

一般来说,C中的数组是二等公民。有数组类型、数组对象甚至数组值,但数组几乎总是通过指向其元素的指针进行操作

这需要程序员做更多的工作(正如您所看到的,您不能只分配数组),但它也给了您更多的灵活性。处理数组的程序通常需要处理不同大小的数组,甚至是直到执行时才能确定的大小。即使允许分配数组,10
int
s的数组和20
int
s的数组也是不同的不兼容类型。如果你有一个固定大小的数组,就像你问题中的代码一样,通常只有一些元素与当前相关;您可能有一个10个元素的数组,但当前仅使用前5个元素。逐个元素处理这样一个数组元素可以更容易地只处理当前活动的元素(您必须跟踪自己)

另一方面,对于结构,成员的数量和类型在定义类型时确定。不能像对待数组那样,通过推进指针来遍历结构的成员,因为成员通常是不同类型的。数组和结构是不同的东西,它们有不同的操作集,对它们来说是有意义的

该语言中有两条规则可以使操作更容易,即:

  • 在大多数(并非所有)上下文中,数组表达式隐式转换为指向数组第一个元素的指针。例外情况如下:
    • 当数组表达式是
      (地址)运算符的操作数时
      
    • 当它是
      sizeof
      的操作数时;及
    • 当它是初始值设定项中的字符串文字时,用于初始化数组对象。)
  • 声明的数组参数,如
    int func(char s[])调整为指针参数:
    int func(char*s)
(有人可能会说,这些规则造成的混乱比它们阻止的要多,但这就是语言的定义方式。)

现在,我假设可以定义语言,或者可以重新定义语言,以便在有意义的情况下允许数组赋值:

struct arraystruct
{
  int t[10];
};


struct arraystruct a,b;

a=b;

也许这样的更改甚至可以在不破坏现有代码的情况下进行。但这需要数组到指针转换规则的另一种特殊情况。它只在固定大小数组的情况下有用,如
a
b
,虽然它们在介绍性编程练习中很常见,但在生产代码中并不常见。

对于历史信息,这可能很有趣:

在B中,声明数组将为数组留出内存,就像C一样,但为变量提供的名称用于定义指向数组的指针。Ritchie在C中对此进行了更改,因此名称“是”数组,但在使用时会衰减为指针:

在今天的C语言中仍然存在的规则是数组类型的值 当它们出现在表达式中时,会转换为指向 构成阵列的第一个对象

这项发明使大多数现有的B代码能够继续工作
int a[10];
int b[10];
/* ... */
a = b; /* Why not? */.