2010-08-14 7 views
10

Ich habe eine Schleife, die von N auf 0 (einschließlich) gehen muss. Meine i Variable ist vom Typ size_t, die normalerweise ohne Vorzeichen ist. Ich verwende derzeit den folgenden Code:For-Schleife Bedingung bei 0 zu stoppen, wenn unsigned Ganzzahlen verwenden?

for (size_t i = N; i != (size_t) -1; --i) { 
    ... 
} 

Ist das korrekt? Gibt es einen besseren Weg, um mit der Bedingung umzugehen?

Danke,

Vincent.

+1

Hmm das ist eine wirklich gute Frage. –

+1

'size_t' ist garantiert unsigniert und Ihre Verwendung von' (size_t) -1' ist korrekt. Sie haben nur ein Problem, wenn N diesem Wert entspricht ... –

+0

Wie wäre es mit {} while (i--)? – supercat

Antwort

7

Ja, es ist korrekt und es ist ein sehr allgemeiner Ansatz. Ich würde nicht darüber nachdenken, es zu ändern.

Arithmetik für vorzeichenlose Integer-Typen verwendet garantiert modulo 2^N Arithmetik (wobei N ist die Anzahl der Wert-Bits in dem Typ) und Verhalten bei Überlauf ist gut definiert.Das Ergebnis wird in den Bereich 0 bis 2^N - 1 durch Addieren oder Subtrahieren von Vielfachen von 2^N (d. H. Modulo 2^N Arithmetik) umgewandelt.

-1 in einen vorzeichenlosen Integertyp umgewandelt (von dem size_t eins ist) konvertiert in 2^N - 1. -- verwendet auch die modulo 2^N Arithmetik für vorzeichenlose Typen, so dass ein vorzeichenloser Typ mit dem Wert 0 auf 2^N - 1 dekrementiert wird. Ihre Schleifenbeendigungsbedingung ist korrekt.

4

Sie können diese verwenden:

for (size_t i = n + 1; i-- > 0;) 
{ 
} 

Hoffnung, das hilft.

+0

Das geht von 'n-1' nach 0, nicht von' n' nach 0. – SoapBox

+0

du hast Recht, ich habe die "inclusive" -Anforderung verpasst, das ist behoben, danke – KeatsPeeks

+1

Es würde nicht im pathologischen Fall funktionieren, wenn 'n'' SIZE_MAX' wäre. Natürlich würde man wahrscheinlich sowieso nicht von "SIZE_MAX" auf 0 iterieren wollen ... – jamesdlin

0

Da unsigned integer in den Höchstwert rollen wird, wenn von Null verringert, können Sie die folgende versuchen, vorausgesetzt N ist weniger dann dieser Maximalwert (bitte jemand mich korrigieren, wenn diese UB ist):

for (size_t i = N; i <= N; i--) { /* ... */ } 
+0

Dies wird wahrscheinlich den Wert von N bei jeder Iteration neu laden, was die Leistung sinnlos beeinträchtigt. –

+2

Woher hast du diese verrückte Idee? Wie unterscheidet sich das von 'für (i = 0; i

3
for (size_t i = N ; i <= N ; i--) { .... } 

Dies würde es tun, weil size_t ein unsigned int ist. Unsigned Ints sind 32bits. Wenn die Variable i den Wert 0 hat, soll Ihre Schleife die Bedingung ausführen. Wenn Sie i-- ausführen, wird der Computer

00000000000000000000000000000000 
-00000000000000000000000000000001 

, die in einem klaren Überlauf ergibt einen Wert von 111.111.111 geben ... 1. Für eine vorzeichenbehaftete Zweierkomplement-Ganzzahl ist dieser Wert eindeutig negativ. Allerdings ist der Typ von i ein vorzeichenloser Int, so dass der Computer 111111 ... 1 als sehr großen positiven Wert interpretiert.

So haben Sie ein paar Optionen:

1) Machen Sie es wie oben und die Schleife machen beenden, wenn ein Überlauf auftritt.

2) Machen Sie die Schleife von i = 0 bis i < = N, aber verwenden Sie (N-i) anstelle von i überall in Ihrer Schleife. Zum Beispiel würde myArray [i] myArray [N-i] werden (um eins nach unten, abhängig davon, was der Wert von N tatsächlich darstellt).

3) Machen Sie die Bedingung Ihrer for-Schleife auszunutzen die Priorität des unären - Betreibers. Als ein anderer Benutzer geschrieben,

for (size_t i = N + 1 ; i-- > 0 ;) { ... } 

Dies wird i auf N + 1, überprüfen, ob die Bedingung N + 1> 0 gilt nach wie vor. Es tut, aber ich habe einen Nebeneffekt, also wird der Wert von i zu i = N dekrementiert. Mach weiter, bis du zu i = 1 kommst. Die Bedingung wird Test sein, 1> 0 ist wahr, der Nebeneffekt tritt auf , dann ist i = 0 und es wird ausgeführt.

+0

Verwenden Sie nicht 'i <= N' als Bedingung. Es wird wahrscheinlich Zeit verschwenden, 'N' aus dem Speicher bei jeder Iteration neu zu laden, und wenn' N' 'SIZE_MAX' ist, haben Sie eine Endlosschleife. –

1

Sie können eine zweite Variable als Schleifenzähler verwenden, um den Bereich der Iteration für zukünftige Prüfer klar zu machen.

for (size_t j=0, i=N; j<=N; ++j, --i) { 
    // code here ignores j and uses i which runs from N to 0 
    ... 
} 
4

Persönlich würde ich nur eine andere Schleife Konstrukt, sondern jeweils ihre eigenen:

size_t i = N; 
do { 
    ... 
} while (i --> 0); 

(Sie nur (i--) als Schleifenbedingung verwenden könnte, aber man sollte nie eine Chance zu verwenden, die passieren, --> "Bediener").

+1

+1 für die Verwendung des '->' -Operators. C-Code soll verschleiert werden, und es macht Spaß :) –

5

Nur weil for einen geeigneten Platz hat, um einen Test zu Beginn jeder Iteration zu setzen, heißt das nicht, dass Sie ihn verwenden müssen. Um N zu 0 einschließlich zu behandeln, sollte der Test am Ende sein, zumindest wenn Sie den maximalen Wert behandeln. Lassen Sie sich nicht davon abhalten, den Test am falschen Ort durchzuführen.

for (size_t i = N;; --i) { 
    ... 
    if (i == 0) break; 
} 

A do-while-Schleife würde auch, aber dann würden Sie zusätzlich i geben bis zur Schleife scoped werden.

1
for (i=N; i+1; i--) 
+0

Beachten Sie, dass, wie jede Lösung außer Do/While-Schleifen und das Äquivalent für/Break-Konstrukt, dies fehlschlägt, wenn "N" ist "SIZE_MAX". –