Was ist der beste Weg, um eine umgekehrte ‘for’-Schleife mit einem vorzeichenlosen Index auszuführen?

Lesezeit: 3 Minuten

Aurons Benutzeravatar
Auron

Mein erster Versuch von für Schleife umkehren das macht sowas n mal war sowas wie:

for ( unsigned int i = n-1; i >= 0; i-- ) {
    ...     
}

Dies scheitert weil in vorzeichenlose Arithmetik i garantiert immer größer oder gleich Null ist, daher ist die Schleifenbedingung immer wahr. Glücklicherweise warnte mich der gcc-Compiler vor einem „sinnlosen Vergleich“, bevor ich mich fragen musste, warum die Schleife unendlich ausgeführt wurde.


Ich suche nach einer eleganten Möglichkeit, dieses Problem zu lösen, wobei Folgendes zu beachten ist:

  1. Es sollte eine rückwärts gerichtete for-Schleife sein.
  2. Der Schleifenindex sollte vorzeichenlos sein.
  3. n ist eine vorzeichenlose Konstante.
  4. Es sollte nicht auf der ‘obskuren’ Ringarithmetik vorzeichenloser Ganzzahlen basieren.

Irgendwelche Ideen? Vielen Dank 🙂

  • if n > größter durch int darstellbarer positiver Wert.

    – Peter Kirkham

    20. März 2009 um 11:38 Uhr

  • Dann verwenden Sie eine lange. Und wenn Ihr Array für längere Zeit zu groß ist, haben Sie ernsthaftere Probleme als unsigned 🙂

    – paxdiablo

    20. März 2009 um 11:41 Uhr

  • Semantik vielleicht? Da ich niemals unter Null sein sollte.

    – Auron

    20. März 2009 um 11:42 Uhr

  • Wer hat etwas von einem Array gesagt?

    anon

    20. März 2009 um 11:42 Uhr

  • @Pax: Dies könnte beispielsweise Code für einen 16-Bit-Prozessor sein, bei dem i über 32767 beginnt. Die Verwendung von etwas Größerem als einem unsigned int wäre ineffizient.

    – Steve Melnikoff

    21. März 2009 um 17:07 Uhr

Benutzeravatar von Skizz
Schizz

Wie wäre es mit:

for (unsigned i = n ; i-- > 0 ; )
{
  // do stuff with i
}

  • @Auron, n ist normalerweise die Länge eines Arrays, daher möchten Sie in den meisten Fällen nicht i == n.

    – Quinmare

    20. März 2009 um 12:07 Uhr

  • Soweit es mich betrifft, ist dies die Standardsprache für Reverse Loop, ich bin überrascht, dass die Leute es noch nie zuvor getroffen haben.

    – Bobin

    20. März 2009 um 13:33 Uhr

  • Sie können es sogar als schreiben i --> 0 das wird visuell die Absicht verraten 😉

    – Patrick Schlüter

    11. Mai 2011 um 8:22 Uhr

  • @HeathHunnicutt – Ganzzahlarithmetik ohne Vorzeichen hat eine gut definierte “Modulo” -Semantik. Out-of-Bounds-Ergebnisse werden stillschweigend umbrochen.

    – Mankarse

    16. Oktober 2011 um 9:08 Uhr

  • @HeathHunnicutt Ganzzahlen ohne Vorzeichen laufen in C nie über oder unter. Nur bei Ganzzahlen mit Vorzeichen haben Unterläufe und Überläufe ein undefiniertes Verhalten. Aus der Norm: unsigned arithmetic does not overflow because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting unsigned integer type..

    – Ruslan

    3. März 2016 um 5:21 Uhr


for ( unsigned int loopIndex = n; loopIndex > 0; --loopIndex ) {
    unsigned int i = loopIndex - 1;
    ...
} 

oder

for ( unsigned int loopIndex = 0; loopIndex < n; ++loopIndex ) {
    unsigned int i = n - loopIndex - 1;
    ...
} 

  • Huch! Ich habe versehentlich einen Kommentar gelöscht, als ich versuchte, meinen eigenen zu löschen. Aus meinem Cache: “Ein klassisches Beispiel für lange Variablennamen, die den Code weniger lesbar machen, IMHO.” — Tut mir leid, ich kann kein Rückgängigmachen finden

    – Lou Franco

    20. März 2009 um 11:40 Uhr

for ( unsigned int i = n; i != 0; i-- ) {
    // do something with i - 1
    ...     
}

Beachten Sie, dass, wenn Sie sowohl C++ als auch C verwenden, die Verwendung von != eine gute Angewohnheit ist, wenn Sie zur Verwendung von Iteratoren wechseln, wo <= usw. möglicherweise nicht verfügbar sind.

  • Außerdem werden Sie bald eine Endlosschleife bemerken, wenn ein Code innerhalb der Schleife noch weiter abnimmt. (und es ist einfacher darüber nachzudenken)

    – xtofl

    20. März 2009 um 12:38 Uhr

Benutzeravatar von idz
idz

Warum nicht einfach:

unsigned int i = n;
while(i--)
{ 
    // use i
}

Dies erfüllt alle im Hauptteil der Frage aufgezählten Anforderungen. Es verwendet nichts, was die Codeüberprüfung wahrscheinlich nicht bestehen oder gegen einen Codierungsstandard verstoßen könnte. Der einzige Einwand, den ich dagegen sehen könnte, ist, ob das OP wirklich auf a bestand for Schleife und kein einfacher Weg, um i = (n-1) .. 0 zu erzeugen.

Benutzeravatar von Pete Kirkham
Peter Kirkham

Ich würde eher verwenden

 for ( unsigned int i = n; i > 0; )  {
    --i;
    ...     
 }

Es ist fast dasselbe wie die Antwort von skizz (es fehlt ein letztes unnötiges Dekrement, aber der Compiler sollte das wegoptimieren) und wird die Codeüberprüfung tatsächlich bestehen. Jeder Codierungsstandard, mit dem ich arbeiten musste, hatte eine Nicht-Mutation in der bedingten Regel.

  • Jetzt dasist ein verstümmeltes for-Konstrukt, das schnell durch eine while-Anweisung ersetzt werden kann! -1 dafür.

    – xtofl

    20. März 2009 um 12:39 Uhr

  • xtofl – Nein, keine while-Anweisung. Skizz zeigt den besten Weg. Bei einer while-Anweisung muss ihre Schleifenvariable außerhalb ihres Gültigkeitsbereichs in einer unabhängigen Anweisung deklariert werden.

    – Svante

    20. März 2009 um 12:55 Uhr

  • Leider würde die Antwort von Skizz in den meisten Shops nicht über die Codeüberprüfung hinausgehen.

    – Peter Kirkham

    20. März 2009 um 13:03 Uhr

  • “No-Mutation in Conditional” – Ich dachte, wir wären Programmierer, keine (Code-)Affen! Regeln sollten dort gebrochen werden, wo der Code darunter leiden würde. Die Verwendung eines ‘i-1’-Indexers ist weitaus schlimmer als eine mutierende Bedingung. Die Reifen, durch die einige dieser Antworten springen, sind einfach hässlich.

    – Schizz

    20. März 2009 um 14:22 Uhr

  • Ich stimme zu, dass die Verwendung eines i-1-Indexers schlechter ist.

    – Peter Kirkham

    20. März 2009 um 14:48 Uhr

Benutzeravatar von vartec
vartec

for ( unsigned int i = n; i > 0; i-- ) {
    ...  
    i-1 //wherever you've been using i   
}

  • Jetzt dasist ein verstümmeltes for-Konstrukt, das schnell durch eine while-Anweisung ersetzt werden kann! -1 dafür.

    – xtofl

    20. März 2009 um 12:39 Uhr

  • xtofl – Nein, keine while-Anweisung. Skizz zeigt den besten Weg. Bei einer while-Anweisung muss ihre Schleifenvariable außerhalb ihres Gültigkeitsbereichs in einer unabhängigen Anweisung deklariert werden.

    – Svante

    20. März 2009 um 12:55 Uhr

  • Leider würde die Antwort von Skizz in den meisten Shops nicht über die Codeüberprüfung hinausgehen.

    – Peter Kirkham

    20. März 2009 um 13:03 Uhr

  • “No-Mutation in Conditional” – Ich dachte, wir wären Programmierer, keine (Code-)Affen! Regeln sollten dort gebrochen werden, wo der Code darunter leiden würde. Die Verwendung eines ‘i-1’-Indexers ist weitaus schlimmer als eine mutierende Bedingung. Die Reifen, durch die einige dieser Antworten springen, sind einfach hässlich.

    – Schizz

    20. März 2009 um 14:22 Uhr

  • Ich stimme zu, dass die Verwendung eines i-1-Indexers schlechter ist.

    – Peter Kirkham

    20. März 2009 um 14:48 Uhr

Vielleicht so? IMHO ist es klar und lesbar. Sie können das if(n>=1) weglassen, wenn es irgendwie implizit bekannt ist.

if(n>=1) {
    // Start the loop at last index
    unsigned int i = n-1;
    do {
       // a plus: you can use i, not i-1 here
    } while( i-- != 0 );
}

Andere Version:

if(n>=1) {
    unsigned int i = n;
    do {
       i--;

    } while( i != 0 );
}

Der erste Code ohne if-Anweisung würde wie folgt aussehen:

unsigned int i = n-1;
do {

} while( i-- != 0 );

1416130cookie-checkWas ist der beste Weg, um eine umgekehrte ‘for’-Schleife mit einem vorzeichenlosen Index auszuführen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy