C不能返回与C ++不同的引用。这是否意味着如果您访问A[i]
,它会在评估表达式时复制元素吗?
例如,如果A
是一个10 int
的数组,A[5]+=1;
只会增加评估A[5]
时构建的临时副本,这与C ++的向量增加不同实际的第六元素本身?
答案 0 :(得分:12)
C有一个叫做“左右”的概念。这有点像参考。它不是一个类型(不是类型系统的一部分),但某些C表达式是' lvalues',只有这样的表达式可以是赋值的左操作数(包括op-assign)或者增量/减量。
由于C没有运算符重载,因此不需要在类型系统中进行区分,因为从来没有必要将事物声明为rvalues vs lvalues。希望在C ++中添加运算符重载,从而引入引用类型,使重载运算符的rvalue / lvalue区分清晰。
答案 1 :(得分:5)
如果确实如此,那么根本无法修改数组,表达式A[5]+=1;
将无法生效!
相反,当您将标量参数传递给函数时,它的行为类似于副本,因为它在返回时不会被修改。但实际上作为指针传递的数组不会被复制(这将是无法承受的代价),并且在返回时可能会有所不同。
答案 2 :(得分:4)
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;
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]
通过其相对于堆栈帧(A
的(结束)的位置来标识rbp
的第6个元素。
关于参考文献的观点是红鲱鱼。 C和C ++都在编译机器代码(可能通过汇编程序)。这些语言的其他功能对A[5]+=1;
的解释或编译方式没有影响。
答案 3 :(得分:2)
C始终在使用A[i]
的数组中读取时复制元素,也就是说,当表达式A[i]
为“rvalue”时。但是,在考虑写入时,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
答案 4 :(得分:0)
不,我的数组索引只是一个指针,因此只传递一个位置而不是整个数组,并且实际内存位置的值会受到影响。
尝试以下代码:
#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;
}