每次访问数组时,C 都会复制元素吗?
Posted
技术标签:
【中文标题】每次访问数组时,C 都会复制元素吗?【英文标题】:Does C copy the element every time you access an array? 【发布时间】:2017-07-23 10:07:25 【问题描述】:与 C++ 不同,C 不能返回引用。这是否意味着如果您访问A[i]
,它将在评估表达式时复制元素?
例如,如果A
是一个由 10 个int
s 组成的数组,那么A[5]+=1;
是否只增加在评估A[5]
时构建的临时副本,这与 C++ 的向量不同,它会增加实际的第六个元素本身?
【问题讨论】:
A[5]
直接取消引用数组元素,不涉及临时副本。
A[5] += 1
递增数组A
的第一个从零开始的元素。如果它不这样做,则编译器有一个错误。不清楚你在问什么。
A[5]+=1
与 A[5] = A[5] + 1
相同,优化编译器将尽可能少地复制,如果有的话,机器语言可以表达。
确保您了解a = 3;
不读取a
... 数组成员访问没有什么不同
【参考方案1】:
C 有一个称为“左值”的概念,它有点像引用。它不是类型(不是类型系统的一部分),但某些 C 表达式是“左值”,并且只有这样的表达式可以是赋值(包括操作赋值)或递增/递减的左操作数。
由于 C 没有运算符重载,因此无需在类型系统中进行区分,因为永远不需要将事物声明为右值与左值。正是在 C++ 中添加运算符重载的愿望导致引入了引用类型,以使重载运算符清楚地区分右值/左值。
【讨论】:
【参考方案2】:如果是这样,您将根本无法修改数组,表达式 A[5]+=1;
将无效!
相反,当您将标量参数传递给函数时,它的行为就像一个副本,因为它在返回时不会被修改。但是实际上作为指针传递的数组不会被复制(这将是难以承受的代价)并且在返回时可能会有所不同。
【讨论】:
【参考方案3】:A[5]+=1;仅在评估 A[5] 时增加构建的临时副本
没有。 A[5]+=1;
将导致 A
的第 6 个元素增加 1。
这很可能通过将A[5]
复制到 CPU 中的寄存器中,将其递增并将值复制回来来实现。
这是一个程序:
int main()
int A[10];
A[5]+=1;
return 0;
这是 gcc 为A[5]+=1;
生成的 x86-64 汇编程序
mov eax, DWORD PTR [rbp-28]
add eax, 1
mov DWORD PTR [rbp-28], eax
这会将DWORD PTR [rbp-28]
移动到 32 位 EAX 累加器中,将其加 1 并将其移回同一位置。
DWORD PTR [rbp-28]
通过其相对于堆栈帧(rbp
)的位置(结束)来标识A
的第 6 个元素。
关于引用的观点是红鲱鱼。 C 和 C++ 都编译为机器代码(可能通过汇编程序)。这些语言还有哪些其他功能不会影响 A[5]+=1;
的解释或编译方式。
【讨论】:
【参考方案4】:当从带有A[i]
的数组中读取 时,C 总是复制一个元素,也就是说,当表达式A[i]
是一个“右值”时。然而,在考虑 writes 时,C 有一个“左值”表达式的概念,它本质上是表达式语法的一个受限子集,可以作为赋值的目标出现:
X = Y
*X = Y
X[i] = Y
X.n = Y
在这些情况下,“表达式”*X
、X[i]
和 X.n
实际上并不计算为值——为方便起见,它们具有与表达式相同的语法,但不一样的语义。您可以将这些视为更像以下内容:
memcpy(&X, &Y, sizeof(Y));
memcpy(&*X, &Y, sizeof(Y));
memcpy(&X[i], &Y, sizeof(Y));
memcpy(&X.n, &Y, sizeof(Y));
或者,或者,将C视为具有多个不同的赋值运算符:
_ = _ // direct assignment
*_ = _ // indirect assignment
_[_] = _ // special case of indirect assignment
_._ = _ // special case of indirect assignment
无论哪种方式,A[5] += 1
之类的赋值都会增加 A
的第六个元素的值,正如您所期望的那样,您可以像这样验证:
int A[1] = 1 ;
A[0] += 5;
printf("%d\n", A[0]); // 6
【讨论】:
【参考方案5】:不,i 数组索引只是一个指针,因此只传递一个位置而不是整个数组,并且实际内存位置的值会受到影响。
试试下面的代码:
#include<stdio.h>
void function(int[]);
int main()
int a[] = 0,1,2,3,4,5,6,7,8,9;
int i;
for(i = 0; i < 10; i++)
printf("%d, ",a[i]);
function(a);
printf("\n");
for(i = 0; i < 10; i++)
printf("%d, ",a[i]);
return 0;
void function(int b[])
int i;
for(i = 0; i < 10; i++)
b[i] *= 10;
OUTPUT
【讨论】:
以上是关于每次访问数组时,C 都会复制元素吗?的主要内容,如果未能解决你的问题,请参考以下文章