2017-07-23 5 views
8

C kann keine Referenzen im Gegensatz zu C++ zurückgeben. Heißt das, wenn Sie auf A[i] zugreifen, wird das Element beim Auswerten des Ausdrucks kopiert?Kopiert C das Element bei jedem Zugriff auf ein Array?

Zum Beispiel, wenn A ist ein Array von 10 int s, nicht inkrementiert A[5]+=1; nur die temporäre Kopie gebaut bei der Bewertung A[5], im Gegensatz zu C++ 's-Vektor, der das tatsächliche sechste Element selbst inkrementiert wird?

+14

'A [5]' dereferenziert das Array-Element direkt, keine temporären beteiligt Kopien. – user0042

+0

'A [5] + = 1 'erhöht das Fitth-Null-basierte Element des Arrays' A '. Wenn es das nicht tut, hat der Compiler einen Fehler. Unklar, was du verlangst. – EJP

+0

'A [5] + = 1' ist genau das gleiche wie' A [5] = A [5] + 1', ein optimierender Compiler würde, wenn überhaupt, so wenige Kopien wie möglich machen Maschinensprache. – nos

Antwort

12

C hat ein Konzept namens "Lvalue", das eine Art Referenz ist. Es ist kein Typ (nicht Teil des Typsystems), aber bestimmte C-Ausdrücke sind "lvalues", und nur solche Ausdrücke können der linke Operand einer Zuweisung (einschließlich einer Op-Zuweisung) oder ein Inkrement/Dekrement sein.

Da C keine Überladung des Operators hat, muss im Typsystem nicht unterschieden werden, da es nie notwendig ist, Dinge als rvalues ​​vs lvalues ​​zu deklarieren. Es war der Wunsch, das Überladen von Operatoren in C++ hinzuzufügen, was zur Einführung von Referenztypen führte, um die Unterscheidung rvalue/lvalue für überlastete Operatoren klar zu machen.

5

Wenn das wahr wäre, könnten Sie Arrays überhaupt nicht ändern und der Ausdruck A[5]+=1; hätte keinen Effekt!

Wenn Sie dagegen ein skalares Argument an eine Funktion übergeben, verhält es sich wie eine Kopie, da es bei der Rückgabe nicht geändert wird. Aber ein Array, tatsächlich als ein Zeiger übergeben, wird nicht kopiert (das wäre unerträglich teuer) und kann bei der Rückkehr anders sein.

2

C immer kopiert ein Element, wenn mit A[i] aus einem Array zu lesen, das heißt, wenn der Ausdruck A[i] ist ein „R-Wert“. Wenn man jedoch schreibt, C eine Vorstellung von „L-Wert“ Ausdrücke hat, die im Wesentlichen eine eingeschränkte Teilmenge der Ausdruckssyntax ist, die zulässig sind als Ziel einer Zuweisung erscheinen:

X = Y 
*X = Y 
X[i] = Y 
X.n = Y 

In diesen Fällen die „Ausdrücke“ *X, X[i] und X.n nicht auswerten tatsächlich auf Werte sie die gleiche Syntax als Ausdrücke, für die Bequemlichkeit, aber nicht die gleiche Semantik. Sie können als so etwas wie diese denken mehr wie folgt aus:

memcpy(&X, &Y, sizeof(Y)); 
memcpy(&*X, &Y, sizeof(Y)); 
memcpy(&X[i], &Y, sizeof(Y)); 
memcpy(&X.n, &Y, sizeof(Y)); 

Oder alternativ, denken Sie an C als mehrere verschiedene Zuweisungsoperatoren mit:

_ = _ // direct assignment 
*_ = _ // indirect assignment 
_[_] = _ // special case of indirect assignment 
_._ = _ // special case of indirect assignment 

So oder so, eine Zuordnung wie A[5] += 1 wird den Wert des sechsten Elements von A an Ort und Stelle erhöhen, wie Sie es erwarten würden, was Sie so bestätigen können:

int A[1] = { 1 }; 
A[0] += 5; 
printf("%d\n", A[0]); // 6 
4

tut A [5] + = 1; nur inkrementieren die temporäre Kopie gebaut bei der Bewertung A [5]

No. A[5]+=1; das 6. Element A verursachen um 1 erhöht werden.

Das wird wahrscheinlich erreicht, indem man A[5] in ein Register in der CPU kopiert, es inkrementiert und den Wert zurückkopiert.

Hier ist ein Programm:

int main(){ 
    int A[10]; 
    A[5]+=1; 
    return 0; 
} 

Hier ist der x86-64-Assembler erzeugt gcc für A[5]+=1;

mov  eax, DWORD PTR [rbp-28] 
    add  eax, 1 
    mov  DWORD PTR [rbp-28], eax 

Das DWORD PTR [rbp-28] in die 32-Bit-EAX Speicher bewegt, addiert 1 zu ihm und bewegt es zurück zum selben Ort.

DWORD PTR [rbp-28] identifiziert das 6. Element von A durch seine Position relativ zum (Ende des) Stapelrahmens (rbp).

Der Punkt über Referenzen ist ein Red-Hering. Sowohl C als auch C++ kompilieren zu Maschinencode (möglicherweise über Assembler). Welche anderen Funktionen die Sprachen haben, hat keinen Einfluss darauf, wie A[5]+=1; interpretiert oder kompiliert wird.

0

Nein, der Array-Index ist nur ein Zeiger, so dass nur ein Speicherort anstelle des gesamten Arrays übergeben wird und der Wert des tatsächlichen Speicherbereichs betroffen ist.

versuchen, den folgenden Code:

#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

Verwandte Themen