首页 > 解决方案 > 阵列衰减和修改

问题描述

在阅读了一些关于为什么 C/C++ 中的数组是不可修改的左值的答案之后,我仍然有点困惑。

根据接受的答案(总结如下):为什么数组类型对象不可修改?

C 的编写方式是在计算数组表达式时计算第一个元素的地址。

这就是为什么你不能做类似的事情

int a[N], b[N];
a = b;

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

这是我感到困惑的时候。

当我们有a = b时,对我来说b应该衰减到一个指针值,指向 的第一个元素是有意义的b

我认为a 也会衰减为指针值,但我不确定。

我的问题是:

怎么会a = b等同于类似的东西3 = 4

不是更相似address of a = address of b吗?

标签: c++arrays

解决方案


由于在您最后几个问题的可衡量程度上,您对数组/指针转换的困惑部分似乎是由于难以理解指针本身。让我们从一个快速的总结开始。

指针基础

指针只是一个普通变量,它保存其他东西的地址作为它的值。换句话说,一个指针指向可以找到其他东西的内存地址。在您通常认为变量保存立即值的地方,例如int a = 5;,指针将简单地保存5存储在内存中的地址。要声明指针本身并将地址分配为其值,您可以使用一元运算'&'符来获取该类型的现有对象的地址。例如int *b = &a;,获取a5存储在内存中的位置)的地址并将该地址分配为指针的值b。(b现在指向a

要引用指针持有的地址处的值,您可以通过在指针名称前使用一元字符来取消引用指针。'*'例如,b保存a(例如b指向a)的地址,因此要获取 保存的地址处的值b,您只需取消引用 b,例如*b

无论对象的类型如何,指针运算都以相同的方式工作,因为type指针的 控制指针运算,例如,使用char *指针,pointer+1指向下一个字节(next char),对于int *指针(正常的 4 字节整数),pointer+1将指向下int一个偏移 4 个字节后的pointer. (所以一个指针,只是一个指针......其中算术由 自动处理type

数组是指针的转换器,它在访问时的第一个元素

继续进行数组指针转换,C 和 C++ 标准都定义了如何array type在访问时将 an 转换为指针,但有 4 个例外。请注意,C++ 标准将依赖于“基本类型”的 C 标准,并将在 C++ 标准中添加定义以在必要时扩展 C 标准。数组/指针转换的基本行为由C11 标准提供 - 6.3.2.1 其他操作数 - 左值、数组和函数指示符 (p3)

§ 6.3.2 Other operands
    6.3.2.1  Lvalues, arrays, and function designators
    Array pointer conversion
    (p3) Except when it is the operand of the sizeof operator, the _Alignof 
    operator, or the unary '&' operator, or is a string literal used to 
    initialize an array, an expression that has type "array of type" is 
    converted to an expression with type "pointer to type" that points to 
    the initial element of the array object and is not an lvalue.

该标准特别定义了数组在访问转换为指向第一个元素的指针时会产生一个不是左值的指针。. 因此,如果您有 arraya和 array b,那么标准本身就禁止您使用以下命令更改该指针所持有的地址:

a = b;

并且,正如评论中提供的示例中所解释的那样,将导致您失去访问a如果允许的元素的能力。

C++ 标准合并了 C 标准中定义的行为,但随后扩展了围绕数组/指针转换的定义,以说明 C 中不存在的类型和对象的使用,但不改变6.3.2.1(p3)的行为.

C++ 标准 7.3.2 数组到指针的转换提供:

§ 7.3.2 Array-to-pointer conversion
  1  An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” 
     can be converted to a prvalue of type “pointer to T”. The temporary 
     materialization conversion ([conv.rval]) is applied. The result is a 
     pointer to the first element of the array.

扩展是 C++ 标准,专门将结果指针定义为纯右值 - 纯右值,而不是 C 定义的“非左值”,并添加了“T 的未知边界数组”语言。

因此,在 C 和 C++ 中,在访问时,数组都会被转换为指向其第一个元素的指针(受 4 中列举的例外的影响§6.3.2.1(p3)),并且生成的指针不能被修改或分配另一个地址。修改的限制与普通指针的行为方式没有任何关系,而仅仅是由于 C/C++ 标准定义转换的方式以及生成的指针类型不能被修改。(所以简短的回答是因为标准说你不能)

仔细检查并确保它对您有意义并且已经深入人心。如果您仍然模糊,请发表评论。重要的部分是理解指针本身。对那些由数组/指针转换产生的指针可以做什么的限制是由标准本身决定的。


推荐阅读