C
Dies erinnerte mich an einen Fehler, auf den ich gestoßen war, als ich C lernte. Leider scheint die ursprüngliche Variante nicht mit einem aktuellen GCC zu funktionieren, aber dies tut es immer noch:
#define ARR_SIZE 1234
int main() {
int i = ARR_SIZE;
int arr[ARR_SIZE];
while(i >= 0) {
(--i)[arr] = 0;
}
i = *(int*)0;
}
Dies schlägt offensichtlich fehl, weil wir einen Nullzeiger dereferenzieren, richtig?
Falsch - eigentlich ist es eine Endlosschleife, da unsere Schleifenbedingung um eins abweicht. Läuft aufgrund der Präfix-Dekrementierung i
von 1023 bis -1. Das heißt, die Zuordnung überschreibt nicht nur alle Elemente in arr
, sondern auch den Speicherort direkt davor - also den i
Speicherort. Bei Erreichen -1
, i
überschrieben sich mit 0
und damit die Schleifenbedingung wieder erfüllt ...
Dies war die ursprüngliche Variante I, die ich nicht mehr reproduzieren kann:
Das Gleiche funktionierte i
, wenn man von 0 aufwärts ging und um eins abbrach. Der neueste GCC speichert immer i
vorher arr
im Speicher. Dies muss in älteren Versionen anders gewesen sein (möglicherweise abhängig von der Reihenfolge der Deklaration). Es war ein tatsächlicher Fehler, den ich in einem meiner ersten Spielzeugprogramme mit Arrays verursachte.
Dies ist auch offensichtlich, wenn Sie wissen, wie Zeiger in C funktionieren, aber es kann überraschend sein, wenn Sie nicht:
Sie könnten denken, dass die Zuweisung zu (--i)[arr]
einen Fehler auslöst, aber es ist gültig und äquivalent zu arr[--i]
. Ein Ausdruck a[x]
ist nur syntaktischer Zucker, für *(a + x)
den der Zeiger auf das indizierte Element berechnet und dereferenziert wird. der zusatz ist natürlich kommutativ und damit äquivalent zu *(x + a)
.