übergeben - c zweidimensionales array




Warum ist es bei Arrays so, dass a[5]== 5[a]? (12)

Wie Joel in Stack Overflow Podcast # 34 in C Programmiersprache (alias: K & R) hervorhebt, wird diese Eigenschaft von Arrays in C erwähnt: a[5] == 5[a]

Joel sagt, dass es wegen der Zeigerarithmetik ist, aber ich verstehe immer noch nicht. Warum ist a[5] == 5[a] ?


Der C-Standard definiert den Operator [] wie folgt:

a[b] == *(a + b)

Daher bewertet a[5] :

*(a + 5)

und 5[a] wird bewerten zu:

*(5 + a)

a ist ein Zeiger auf das erste Element des Arrays. a[5] ist der Wert, der 5 Elemente weiter von a , was gleich ist wie *(a + 5) , und aus der Grundschulmathematik wissen wir, dass diese gleich sind (Addition ist commutative ).


Eine Sache scheint niemand über Dinahs Problem mit der sizeof erwähnt zu haben:

Sie können einem Zeiger nur eine Ganzzahl hinzufügen, Sie können nicht zwei Zeiger zusammen hinzufügen. Auf diese Weise weiß der Compiler beim Hinzufügen eines Zeigers zu einer Ganzzahl oder einer Ganzzahl zu einem Zeiger immer, welches Bit eine Größe hat, die berücksichtigt werden muss.


Für Zeiger in C haben wir

a[5] == *(a + 5)

und auch

5[a] == *(5 + a)

Daher gilt a[5] == 5[a].


Ich denke, etwas wird von den anderen Antworten übersehen.

Ja, p[i] ist per Definition äquivalent zu *(p+i) , was (weil Addition kommutativ ist) äquivalent zu *(i+p) , was (wiederum durch die Definition des [] -Operators) äquivalent ist zu i[p] .

(Und in array[i] wird der Array-Name implizit in einen Zeiger auf das erste Element des Arrays konvertiert.)

Aber die Kommutativität der Addition ist in diesem Fall nicht so offensichtlich.

Wenn beide Operanden vom selben Typ oder sogar von verschiedenen numerischen Typen sind, die zu einem gemeinsamen Typ hochgestuft werden, ergibt sich eine vollständige Kommutativität: x + y == y + x .

Aber in diesem Fall sprechen wir speziell über Zeigerarithmetik, wobei ein Operand ein Zeiger und der andere eine ganze Zahl ist. (Ganzzahl + Ganzzahl ist eine andere Operation, und Zeiger + Zeiger ist Unsinn.)

Die C-Standardbeschreibung des + Operators ( N1570 6.5.6) sagt:

Für die Addition müssen beide Operanden einen arithmetischen Typ haben, oder ein Operand soll ein Zeiger auf einen vollständigen Objekttyp sein und der andere soll einen Integer-Typ haben.

Es hätte genauso gut sagen können:

Beide Operanden müssen entweder einen arithmetischen Typ haben, oder der linke Operand soll ein Zeiger auf einen vollständigen Objekttyp sein, und der rechte Operand soll einen Integer-Typ haben.

In diesem Fall wären sowohl i + p als auch i[p] illegal.

In C ++ haben wir wirklich zwei Sätze überladener + Operatoren, die wie folgt beschrieben werden können:

pointer operator+(pointer p, integer i);

und

pointer operator+(integer i, pointer p);

von denen nur das erste wirklich notwendig ist.

Warum ist es so?

C ++ erbte diese Definition von C, die es von B erhielt (die Kommutativität der Array-Indexierung wird explizit in der Benutzerreferenz B von 1972 erwähnt), die es von BCPL (Handbuch von 1967) erhielt, was es möglicherweise von even erhalten hat frühere Sprachen (CPL? Algol?).

Die Idee, dass die Array-Indizierung als Addition definiert ist und dass die Addition, selbst eines Zeigers und einer Ganzzahl, kommutativ ist, geht viele Jahrzehnte zurück in die A-Vorfahren von C.

Diese Sprachen waren viel weniger typisiert als das moderne C. Insbesondere wurde die Unterscheidung zwischen Zeigern und ganzen Zahlen oft ignoriert. (Frühere C-Programmierer verwendeten manchmal Zeiger als vorzeichenlose Ganzzahlen, bevor das unsigned Schlüsselwort zur Sprache hinzugefügt wurde.) Die Idee, die Addition nichtkommutativ zu machen, weil die Operanden unterschiedlicher Art sind, wäre den Entwicklern dieser Sprachen wahrscheinlich nicht eingefallen . Wenn ein Benutzer zwei "Dinge" hinzufügen wollte, ob diese "Dinge" Ganzzahlen, Zeiger oder etwas anderes sind, war es der Sprache nicht möglich, dies zu verhindern.

Und im Laufe der Jahre hätte jede Änderung dieser Regel den bestehenden Code durchbrochen (obwohl der 1989 ANSI C-Standard eine gute Gelegenheit gewesen wäre).

Das Ändern von C und / oder C ++, um den Zeiger auf die linke und die ganze Zahl auf der rechten Seite setzen zu müssen, könnte zwar vorhandenen Code zerstören, aber es würde kein Verlust an echter Ausdruckskraft auftreten.

Also haben wir nun arr[3] und 3[arr] genau dasselbe, obwohl die letztere Form niemals außerhalb der IOCCC erscheinen sollte.


Ich weiß, dass die Frage beantwortet ist, aber ich konnte nicht widerstehen, diese Erklärung zu teilen.

Ich erinnere mich an Principles of Compiler Design, nehmen wir an, a ist ein int Array und die Größe von int ist 2 Bytes, & Base-Adresse für a ist 1000.

Wie a[5] funktioniert ->

Base Address of your Array a + (5*size of(data type for array a))
i.e. 1000 + (5*2) = 1010

Damit,

Ähnlich, wenn der c-Code in 3-Adressen-Code unterteilt ist, wird 5[a] ->

Base Address of your Array a + (size of(data type for array a)*5)
i.e. 1000 + (2*5) = 1010 

Im Grunde weisen also beide Aussagen auf den gleichen Ort im Speicher und daher a[5] = 5[a] .

Diese Erklärung ist auch der Grund, warum negative Indizes in Arrays in C funktionieren.

dh wenn ich auf a[-5] zugreife, wird es mir geben

Base Address of your Array a + (-5 * size of(data type for array a))
i.e. 1000 + (-5*2) = 990

Es wird mir Objekt an Position 990 zurückgeben.


In C-Arrays sind arr[3] und 3[arr] gleich und ihre entsprechenden Zeigerbezeichnungen sind *(arr + 3) bis *(3 + arr) . Im Gegensatz dazu ist [arr]3 oder [3]arr nicht korrekt und führt zu einem Syntaxfehler, da (arr + 3)* und (3 + arr)* keine gültigen Ausdrücke sind. Der Grund dafür ist, dass der Dereferenzoperator vor die Adresse gesetzt werden sollte, die durch den Ausdruck geliefert wird, nicht nach der Adresse.


In C-Sprache sind Zeiger und Array sehr nahe beieinander, ein Array kann in Form des pointer . Der Name des Arrays ist ein Zeiger auf sein erstes Element. Wenn also acData ein Array von Zeichen ist, dann ist "acData" die Adresse seines ersten Elements. Sie können auch sagen, dass "acData" dem & acData [0] ähnlich ist.

Nach dem C-Standard können wir ein 1D-Array in Form eines Zeigers darstellen.

Siehe den folgenden Ausdruck,

acData [i] = * (acData + i); ---------> 1D-Array in Form eines Zeigers

Also wenn i = 5;

cData [5] = * (acData +5);

Wir können auch den Ausdruck in folgender Form darstellen:

cData [5] = * (5 + acData);

So, jetzt können wir schreiben

cData [5] = 5 [cData];

Siehe den folgenden Code,

#include <stdio.h>

int main(int argc, char *argv[]) {

 char cData  [] = {'w', 'o', 'r', 'l' ,'d' }; // character array

 int index = 0;

 for(index = 0; index < sizeof(cData ); ++index)
 {
     printf("Array element access by pointer = %c\n\n",cData[index]);

     printf("Array element access by   array = %c\n\n",index[cData]);
 }


    return 0;
}

Referenzen, https://aticleworld.com/array-in-c/


Keine Antwort, sondern nur ein paar Denkanstöße. Wenn die Klasse einen Index / Index-Operator überladen hat, funktioniert der Ausdruck 0[x] nicht:

class Sub
{
public:
    int operator [](size_t nIndex)
    {
        return 0;
    }   
};

int main()
{
    Sub s;
    s[0];
    0[s]; // ERROR 
}

Da wir keinen Zugriff auf die Klasse " int" haben , kann dies nicht durchgeführt werden:

class int
{
   int operator[](const Sub&);
};

Nun, das ist eine Funktion, die nur wegen der Sprachunterstützung möglich ist.

Der Compiler interpretiert a[i] als *(a+i) und der Ausdruck 5[a] ergibt *(5+a) . Da Addition kommutativ ist, stellt sich heraus, dass beide gleich sind. Daher wird der Ausdruck als true ausgewertet.


Um die Frage wörtlich zu beantworten. Es ist nicht immer wahr, dass x == x

double zero = 0.0;
double a[] = { 0,0,0,0,0, zero/zero}; // NaN
cout << (a[5] == 5[a] ? "true" : "false") << endl;

Drucke

false

Weil Array-Zugriff in Bezug auf Zeiger definiert ist. a[i] ist definiert als *(a + i) , was kommutativ ist.


in C-Compiler

a[i]
i[a]
*(a+i)

sind verschiedene Möglichkeiten, auf ein Element in einem Array zu verweisen! (Überhaupt nicht seltsam)





pointer-arithmetic