gpt4 book ai didi

c - 为什么数组类型对象不可修改?

转载 作者:行者123 更新时间:2023-12-02 16:16:58 24 4
gpt4 key购买 nike

据说here

The term modifiable lvalue is used to emphasize that the lvalue allows the designated object to be changed as well as examined. The following object types are lvalues, but not modifiable lvalues:

  • An array type
  • An incomplete type
  • A const-qualified type
  • A structure or union type with one of its members qualified as a const type

因为这些左值不可修改,所以它们不能出现在赋值语句的左侧。
为什么数组类型对象不可修改?写的对不对
int i = 5, a[10] = {0};    
a[i] = 1;
?
还有,什么是不完整类型?

最佳答案

假设声明

int a[10];

那么以下所有情况都为真:
  • 表达式的类型 a是“int”的10个元素数组;除非 asizeof 的操作数或一元&运算符,表达式将转换为“指向 int 的指针”类型的表达式,其值将是数组中第一个元素的地址;
  • 表达式的类型 a[i]int ;它指的是存储为 i 的整数对象'数组的第一个元素;
  • 表达式 a可能不是赋值的目标,因为 C 不像其他变量那样对待数组,所以你不能写类似 a = b 的东西。或 a = malloc(n * sizeof *a)或类似的东西。

  • 你会注意到我一直在强调“表达”这个词。我们留出的用于存放 10 个整数的内存块与我们用来引用该内存块的符号(表达式)之间存在差异。我们可以用表达式 a 来引用它。 .我们还可以创建一个指向该数组的指针:
    int (*ptr)[10] = &a;

    表达式 *ptr也有类型“ int 的10 元素数组”,它指的是与 a 相同的内存块。指。

    C 不会像对待其他类型的表达式一样对待数组表达式( a*ptr ),区别之一是数组类型的表达式可能不是赋值的目标。您不能重新分配 a引用不同的数组对象(与表达式 *ptr 相同)。您可以为 a[i] 分配一个新值或 (*ptr)[i] (改变每个数组元素的值),你可以赋值 ptr指向不同的数组:
    int b[10], c[10];
    .....
    ptr = &b;
    .....
    ptr = &c;

    至于第二个问题...

    不完整的类型缺少大小信息;声明如
    struct foo;
    int bar[];
    union bletch;

    所有这些都会创建不完整的类型,因为编译器没有足够的信息来确定为该类型的对象留出多少存储空间。您不能创建不完整类型的对象;例如,您不能声明
    struct foo myFoo;

    除非您完成 struct foo 的定义.但是,您可以创建指向不完整类型的指针;例如,您可以声明
    struct foo *myFooPtr;

    没有完成 struct foo 的定义因为指针只存储对象的地址,您不需要知道类型的大小。这使得定义自引用类型成为可能,例如
    struct node {
    T key; // for any type T
    Q val; // for any type Q
    struct node *left;
    struct node *right;
    };
    struct node 的类型定义直到我们结束时才完成 } .因为我们可以声明一个指向不完整类型的指针,所以我们没问题。但是,我们无法将结构定义为
    struct node {
    ... // same as above
    struct node left;
    struct node right;
    };

    因为当我们声明 left 时类型不完整和 right成员(member),也因为每个 leftright每个成员将包含 leftright他们自己的成员,每个成员都将包含 leftright他们自己的成员,等等等等。

    这对结构体和 union 体来说很好,但是呢
    int bar[];

    ???

    我们已经声明了符号 bar并表示它将是一个数组类型,但此时大小未知。最终我们必须用一个大小来定义它,但这样符号就可以用在数组大小没有意义或没有必要的上下文中。不过,没有一个好的、非人为的例子来说明这一点。

    编辑

    在这里回复评论,因为评论部分没有空间来写我想写的东西(今晚我心情很复杂)。你问:

    Does it mean every variables are expression?



    这意味着任何变量都可以是表达式或表达式的一部分。以下是 language standard 的方法定义术语表达式:

    6.5 Expressions
    1 An expression is a sequence of operators and operands that specifies computation of a value, or that designates an object or a function, or that generates side effects, or thatperforms a combination thereof.


    例如,变量 a所有本身都算作一种表达;它指定我们定义的数组对象来保存 10 个整数值。它还计算数组的第一个元素的地址。变量 a也可以是更大表达式的一部分,如 a[i] ;运算符是下标运算符 []操作数是变量 ai .此表达式指定数组的单个成员,并将其计算为当前存储在该成员中的值。该表达式又可以是更大表达式的一部分,例如 a[i] = 0 .

    And also let me clear that, in the declaration int a[10], does a[] stands for array type



    对,就是这样。

    在 C 中,声明基于表达式的类型,而不是对象的类型。如果您有一个名为 y 的简单变量存储 int值,并且您想访问该值,只需使用 y在一个表达式中,比如
    x = y;

    表达式的类型 yint ,所以 y的声明写了
    int y;

    另一方面,如果您有一个数组 int值,并且您想要访问特定元素,您可以使用数组名称和索引以及下标运算符来访问该值,例如
    x = a[i];

    表达式的类型 a[i]int ,所以数组的声明写成
    int arr[N]; // for some value N.  
    int 的“ arr -ness”由类型说明符 int 给出; arr 的“数组性”由声明者 arr[N] 给出.声明符为我们提供了被声明对象的名称( arr )以及一些类型说明符未给出的附加类型信息(“是一个 N 元素数组”)。声明“读”为
        a       -- a
    a[N] -- is an N-element array
    int a[N]; -- of int

    编辑2

    毕竟,我还没有告诉你数组表达式是不可修改左值的真正原因。所以这是这本书的另一章答案。

    C 并没有完全从丹尼斯·里奇 (Dennis Ritchie) 的头脑中形成;它源自一种更早的语言 B(源自 BCPL)。1 B 是一种“无类型”语言;它没有整数、浮点数、文本、记录等的不同类型。相反,一切都只是一个固定长度的单词或“单元格”(本质上是一个无符号整数)。内存被视为一个线性的单元阵列。当你在 B 中分配了一个数组时,比如
    auto V[10];

    编译器分配了 11 个单元格;数组本身的 10 个连续单元格,加上一个绑定(bind)到 V 的单元格,其中包含第一个单元格的位置:
        +----+
    V: | | -----+
    +----+ |
    ... |
    +----+ |
    | | <----+
    +----+
    | |
    +----+
    | |
    +----+
    | |
    +----+
    ...

    当 Ritchie 添加 struct键入 C,他意识到这种安排给他带来了一些问题。例如,他想创建一个 struct 类型来表示文件或目录表中的条目:
    struct {
    int inumber;
    char name[14];
    };

    他希望结构不仅以抽象方式描述条目,而且还表示实际文件表条目中的位,其中没有额外的单元格或单词来存储数组中第一个元素的位置。所以他摆脱了它——他没有留出一个单独的位置来存储第一个元素的地址,而是编写了 C,这样在计算数组表达式时将计算第一个元素的地址。

    这就是为什么你不能做这样的事情
    int a[N], b[N];
    a = b;

    因为两者 ab评估该上下文中的指针值;相当于写 3 = 4 .内存中没有任何东西实际存储数组中第一个元素的地址;编译器只是在翻译阶段计算它。

    1.本文均摘自论文 The Development of the C Language

    关于c - 为什么数组类型对象不可修改?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17687429/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com