Gibt es einen Unterschied in ++i
und i++
in einer for
Schleife? Ist es einfach eine Syntaxsache?
Gibt es einen Unterschied in ++i
und i++
in einer for
Schleife? Ist es einfach eine Syntaxsache?
Antworten:
a ++ wird als Postfix bezeichnet.
addiere 1 zu a, gibt den alten Wert zurück.
++ a ist als Präfix bekannt.
addiere 1 zu a, gibt den neuen Wert zurück.
C #:
string[] items = {"a","b","c","d"};
int i = 0;
foreach (string item in items)
{
Console.WriteLine(++i);
}
Console.WriteLine("");
i = 0;
foreach (string item in items)
{
Console.WriteLine(i++);
}
Ausgabe:
1
2
3
4
0
1
2
3
foreach
und while
Schleifen hängen davon ab, welchen Inkrementtyp Sie verwenden. Bei for-Schleifen wie unten macht es keinen Unterschied, da Sie nicht den Rückgabewert von i verwenden:
for (int i = 0; i < 5; i++) { Console.Write(i);}
Console.WriteLine("");
for (int i = 0; i < 5; ++i) { Console.Write(i); }
0 1 2 3 4
0 1 2 3 4
Wenn der ausgewertete Wert verwendet wird, wird die Art des Inkrements signifikant:
int n = 0;
for (int i = 0; n < 5; n = i++) { }
Pre-Inkrement ++ i erhöht den Wert von i und wertet den neuen inkrementierten Wert aus.
int i = 3;
int preIncrementResult = ++i;
Assert( preIncrementResult == 4 );
Assert( i == 4 );
Nach dem Inkrementieren von i ++ wird der Wert von i erhöht und auf den ursprünglichen nicht inkrementierten Wert ausgewertet.
int i = 3;
int postIncrementResult = i++;
Assert( postIncrementtResult == 3 );
Assert( i == 4 );
In C ++ wird normalerweise das Vorinkrement bevorzugt, wenn Sie eines von beiden verwenden können.
Dies liegt daran, dass der Compiler bei Verwendung von Post-Inkrement möglicherweise Code generieren muss, der eine zusätzliche temporäre Variable erstellt. Dies liegt daran, dass sowohl der vorherige als auch der neue Wert der inkrementierten Variablen irgendwo gespeichert werden müssen, da sie möglicherweise an anderer Stelle im ausgewerteten Ausdruck benötigt werden.
Zumindest in C ++ kann es also einen Leistungsunterschied geben, der Sie bei der Auswahl der zu verwendenden Elemente unterstützt.
Dies ist hauptsächlich dann nur dann ein Problem, wenn die inkrementierte Variable ein benutzerdefinierter Typ mit einem überschriebenen ++ - Operator ist. Für primitive Typen (int usw.) gibt es keinen Leistungsunterschied. Es lohnt sich jedoch, sich an den Operator vor dem Inkrementieren als Richtlinie zu halten, es sei denn, der Operator nach dem Inkrementieren ist definitiv das, was erforderlich ist.
Weitere Diskussionen finden Sie hier:
https://web.archive.org/web/20170405054235/http://en.allexperts.com/q/C-1040/Increment-operators.htm
Wenn Sie in C ++ STL verwenden, verwenden Sie möglicherweise for-Schleifen mit Iteratoren. Diese haben hauptsächlich überschriebene ++ - Operatoren, daher ist es eine gute Idee, sich an das Vorinkrementieren zu halten. Compiler werden jedoch immer intelligenter, und neuere können möglicherweise Optimierungen durchführen, die bedeuten, dass es keinen Leistungsunterschied gibt - insbesondere, wenn der zu inkrementierende Typ in der Header-Datei inline definiert wird (wie dies bei STL-Implementierungen häufig der Fall ist), damit der Compiler sehen kann, wie Die Methode ist implementiert und kann dann wissen, welche Optimierungen sicher durchgeführt werden können. Trotzdem lohnt es sich wahrscheinlich immer noch, sich an das Vorinkrementieren zu halten, da Schleifen häufig ausgeführt werden und dies bedeutet, dass ein kleiner Leistungsverlust bald verstärkt werden könnte.
In anderen Sprachen wie C #, in denen der ++ - Operator nicht überladen werden kann, gibt es keinen Leistungsunterschied. In einer Schleife zum Vorrücken der Schleifenvariablen werden die Operatoren vor und nach dem Inkrementieren äquivalent.
Korrektur: Überladen von ++ in C # ist zulässig. Es scheint jedoch, dass Sie in C # im Vergleich zu C ++ die Vor- und Nachversionen nicht unabhängig voneinander überladen können. Wenn das Ergebnis des Aufrufs von ++ in C # keiner Variablen zugewiesen oder als Teil eines komplexen Ausdrucks verwendet wird, würde der Compiler die Vor- und Nachversionen von ++ auf Code reduzieren, der eine gleichwertige Leistung erbringt.
In C # gibt es keinen Unterschied, wenn es in einer for-Schleife verwendet wird .
for (int i = 0; i < 10; i++) { Console.WriteLine(i); }
gibt das gleiche aus wie
for (int i = 0; i < 10; ++i) { Console.WriteLine(i); }
Wie andere bereits betont haben, habe ich bei der allgemeinen Verwendung von i ++ und ++ einen subtilen, aber signifikanten Unterschied:
int i = 0;
Console.WriteLine(i++); // Prints 0
int j = 0;
Console.WriteLine(++j); // Prints 1
i ++ liest den Wert von i und erhöht ihn dann.
++ i erhöht den Wert von i und liest ihn dann.
++i
und i++
führen dieselben Vorgänge in derselben Reihenfolge aus: temporäre Kopie von erstellen i
; Erhöhen Sie den temporären Wert, um einen neuen Wert zu erzeugen (um den temporären Wert nicht zu überschreiben). Speichern Sie den neuen Wert in i
; Wenn ++i
das Ergebnis zurückgegeben wird, ist dies der neue Wert. Wenn i++
das Ergebnis zurückgegeben wird, handelt es sich um die temporäre Kopie. Detailliertere Antwort hier: stackoverflow.com/a/3346729/3330348
Die Frage ist:
Gibt es einen Unterschied zwischen ++ i und i ++ in einer for-Schleife?
Die Antwort lautet: Nein .
Warum muss jede zweite Antwort detaillierte Erklärungen zum Inkrementieren vor und nach dem Inkrementieren enthalten, wenn dies nicht einmal gefragt wird?
Diese for-Schleife:
for (int i = 0; // Initialization
i < 5; // Condition
i++) // Increment
{
Output(i);
}
Würde ohne Verwendung von Schleifen in diesen Code übersetzen:
int i = 0; // Initialization
loopStart:
if (i < 5) // Condition
{
Output(i);
i++ or ++i; // Increment
goto loopStart;
}
Ist es jetzt wichtig, ob Sie hier i++
oder ++i
als Inkrement setzen? Nein, der Rückgabewert der Inkrementierungsoperation ist unbedeutend. i
wird NACH der Ausführung des Codes erhöht, der sich innerhalb des for-Schleifenkörpers befindet.
Da Sie nach dem Unterschied in einer Schleife fragen, meinen Sie das wohl
for(int i=0; i<10; i++)
...;
In diesem Fall haben Sie in den meisten Sprachen keinen Unterschied: Die Schleife verhält sich unabhängig davon, ob Sie schreiben i++
und ++i
. In C ++ können Sie Ihre eigenen Versionen der ++ - Operatoren schreiben und separate Bedeutungen für diese definieren, wenn i
es sich um einen benutzerdefinierten Typ handelt (z. B. Ihre eigene Klasse).
Der Grund, warum es oben nicht wichtig ist, ist, dass Sie den Wert von nicht verwenden i++
. Eine andere Sache ist, wenn Sie es tun
for(int i=0, a = 0; i<10; a = i++)
...;
Nun gibt es einen Unterschied, denn wie andere betonen, i++
bedeutet dies Inkrementieren, aber auf den vorherigen Wert auswerten , aber Inkrementieren++i
bedeuten , aber auswerteni
(daher würde es auf den neuen Wert auswerten). Im obigen Fall a
wird der vorherige Wert von i zugewiesen, während i inkrementiert wird.
Wie dieser Code zeigt (siehe die entschlüsselte MSIL in den Kommentaren), unterscheidet der C # 3-Compiler in einer for-Schleife nicht zwischen i ++ und ++ i. Wenn der Wert von i ++ oder ++ i verwendet würde, würde es definitiv einen Unterschied geben (dies wurde in Visutal Studio 2008 / Release Build kompiliert):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PreOrPostIncrement
{
class Program
{
static int SomethingToIncrement;
static void Main(string[] args)
{
PreIncrement(1000);
PostIncrement(1000);
Console.WriteLine("SomethingToIncrement={0}", SomethingToIncrement);
}
static void PreIncrement(int count)
{
/*
.method private hidebysig static void PreIncrement(int32 count) cil managed
{
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] int32 i)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0014
IL_0004: ldsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0010: ldloc.0
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: ldarg.0
IL_0016: blt.s IL_0004
IL_0018: ret
} // end of method Program::PreIncrement
*/
for (int i = 0; i < count; ++i)
{
++SomethingToIncrement;
}
}
static void PostIncrement(int count)
{
/*
.method private hidebysig static void PostIncrement(int32 count) cil managed
{
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] int32 i)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0014
IL_0004: ldsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0010: ldloc.0
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: ldarg.0
IL_0016: blt.s IL_0004
IL_0018: ret
} // end of method Program::PostIncrement
*/
for (int i = 0; i < count; i++)
{
SomethingToIncrement++;
}
}
}
}
Eins (++ i) ist Vorinkrement, eins (i ++) ist Nachinkrement. Der Unterschied besteht darin, welcher Wert sofort vom Ausdruck zurückgegeben wird.
// Psuedocode
int i = 0;
print i++; // Prints 0
print i; // Prints 1
int j = 0;
print ++j; // Prints 1
print j; // Prints 1
Edit: Woops, ignorierte die Loop-Seite der Dinge völlig. Es gibt keinen tatsächlichen Unterschied zwischen for-Schleifen, wenn es sich um den 'Step'-Teil handelt (for (...; ...;)), aber in anderen Fällen kann er ins Spiel kommen.
Es gibt keinen Unterschied, ob Sie den Wert nach dem Inkrementieren in der Schleife nicht verwenden.
for (int i = 0; i < 4; ++i){
cout<<i;
}
for (int i = 0; i < 4; i++){
cout<<i;
}
Beide Schleifen geben 0123 aus.
Der Unterschied ergibt sich jedoch, wenn Sie den Wert nach dem Inkrementieren / Dekrementieren in Ihrer Schleife wie folgt verwenden:
Pre-Increment-Schleife:
for (int i = 0,k=0; i < 4; k=++i){
cout<<i<<" ";
cout<<k<<" ";
}
Ausgabe: 0 0 1 1 2 2 3 3
Post-Increment-Schleife:
for (int i = 0, k=0; i < 4; k=i++){
cout<<i<<" ";
cout<<k<<" ";
}
Ausgabe: 0 0 1 0 2 1 3 2
Ich hoffe, der Unterschied wird durch den Vergleich der Ausgabe deutlich. Hierbei ist zu beachten, dass das Inkrementieren / Dekrementieren immer am Ende der for-Schleife durchgeführt wird und daher die Ergebnisse erklärt werden können.
Hier ist ein Java-Beispiel und der Byte-Code, Post- und Pre-Increment zeigen keinen Unterschied im Bytecode:
public class PreOrPostIncrement {
static int somethingToIncrement = 0;
public static void main(String[] args) {
final int rounds = 1000;
postIncrement(rounds);
preIncrement(rounds);
}
private static void postIncrement(final int rounds) {
for (int i = 0; i < rounds; i++) {
somethingToIncrement++;
}
}
private static void preIncrement(final int rounds) {
for (int i = 0; i < rounds; ++i) {
++somethingToIncrement;
}
}
}
Und nun zum Bytecode (javap -private -c PreOrPostIncrement):
public class PreOrPostIncrement extends java.lang.Object{
static int somethingToIncrement;
static {};
Code:
0: iconst_0
1: putstatic #10; //Field somethingToIncrement:I
4: return
public PreOrPostIncrement();
Code:
0: aload_0
1: invokespecial #15; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: sipush 1000
3: istore_1
4: sipush 1000
7: invokestatic #21; //Method postIncrement:(I)V
10: sipush 1000
13: invokestatic #25; //Method preIncrement:(I)V
16: return
private static void postIncrement(int);
Code:
0: iconst_0
1: istore_1
2: goto 16
5: getstatic #10; //Field somethingToIncrement:I
8: iconst_1
9: iadd
10: putstatic #10; //Field somethingToIncrement:I
13: iinc 1, 1
16: iload_1
17: iload_0
18: if_icmplt 5
21: return
private static void preIncrement(int);
Code:
0: iconst_0
1: istore_1
2: goto 16
5: getstatic #10; //Field somethingToIncrement:I
8: iconst_1
9: iadd
10: putstatic #10; //Field somethingToIncrement:I
13: iinc 1, 1
16: iload_1
17: iload_0
18: if_icmplt 5
21: return
}
Ja da ist. Die Differenz liegt im Rückgabewert. Der Rückgabewert von "++ i" ist der Wert nach dem Inkrementieren von i. Die Rückgabe von "i ++" ist der Wert vor dem Inkrementieren. Dies bedeutet, dass der Code wie folgt aussieht:
int a = 0;
int b = ++a; // a is incremented and the result after incrementing is saved to b.
int c = a++; // a is incremented again and the result before incremening is saved to c.
Daher wäre a 2 und b und c wären jeweils 1.
Ich könnte den Code folgendermaßen umschreiben:
int a = 0;
// ++a;
a = a + 1; // incrementing first.
b = a; // setting second.
// a++;
c = a; // setting first.
a = a + 1; // incrementing second.
In beiden Fällen gibt es keinen tatsächlichen Unterschied. ' i
' Wird um 1 erhöht.
Es gibt jedoch einen Unterschied, wenn Sie es in einem Ausdruck verwenden, zum Beispiel:
int i = 1;
int a = ++i;
// i is incremented by one and then assigned to a.
// Both i and a are now 2.
int b = i++;
// i is assigned to b and then incremented by one.
// b is now 2, and i is now 3
++ i und i ++ bieten mehr als Schleifen und Leistungsunterschiede. ++ i gibt einen l-Wert zurück und i ++ gibt einen r-Wert zurück. Basierend darauf gibt es viele Dinge, die Sie mit (++ i) tun können, aber nicht mit (i ++).
1- It is illegal to take the address of post increment result. Compiler won't even allow you.
2- Only constant references to post increment can exist, i.e., of the form const T&.
3- You cannot apply another post increment or decrement to the result of i++, i.e., there is no such thing as I++++. This would be parsed as ( i ++ ) ++ which is illegal.
4- When overloading pre-/post-increment and decrement operators, programmers are encouraged to define post- increment/decrement operators like:
T& operator ++ ( )
{
// logical increment
return *this;
}
const T operator ++ ( int )
{
T temp( *this );
++*this;
return temp;
}
Es verwirrt mich, warum so Leute den Inkrementausdruck in for-Schleife als i ++ schreiben können.
In einer for-Schleife, wenn die 3. Komponente eine einfache Inkrementanweisung ist, wie in
for (i=0; i<x; i++)
oder
for (i=0; i<x; ++i)
Es gibt keinen Unterschied in den resultierenden Ausführungen.
Wie @Jon B sagt, gibt es keinen Unterschied in einer for-Schleife.
In einer while
oder- do...while
Schleife können Sie jedoch einige Unterschiede feststellen, wenn Sie einen Vergleich mit dem ++i
oder durchführeni++
while(i++ < 10) { ... } //compare then increment
while(++i < 10) { ... } //increment then compare
In Javascript kann aus folgenden Gründen i ++ besser verwendet werden:
var i=1;
alert(i++); // before, 1. current, 1. after, 2.
alert(i); // before, 2. current, 2. after, 2.
alert(++i); // before, 2. current, 3 after, 3.
Während Arrays (ich denke alle) und einige andere Funktionen und Aufrufe 0 als Ausgangspunkt verwenden, müssten Sie i auf -1 setzen, damit die Schleife mit dem Array funktioniert, wenn Sie ++ i verwenden .
Bei Verwendung von i ++ verwendet der folgende Wert den erhöhten Wert. Man könnte sagen, i ++ ist die Art und Weise, wie Menschen zählen, weil man mit einer 0 beginnen kann .
Um zu verstehen, was eine FOR- Schleife tut
Das obige Bild zeigt, dass FOR in WHILE konvertiert werden kann , da sie letztendlich denselben Assembler-Code haben (zumindest in gcc). So können wir FOR in ein paar Teile zerlegen, um zu verstehen, was es tut.
for (i = 0; i < 5; ++i) {
DoSomethingA();
DoSomethingB();
}
ist gleich der WHILE- Version
i = 0; //first argument (a statement) of for
while (i < 5 /*second argument (a condition) of for*/) {
DoSomethingA();
DoSomethingB();
++i; //third argument (another statement) of for
}
Dies bedeutet, dass Sie FOR als einfache Version von WHILE verwenden können :
Das erste Argument von FOR (int i) wird außerhalb vor der Schleife ausgeführt.
Das dritte Argument von FOR (i ++ oder ++ i) wird in der letzten Zeile der Schleife ausgeführt.
TL: DR: Egal ob
i++
oder++i
, wir wissen, dass sie, wenn sie eigenständig sind, keinen Unterschied machen, sondern +1 für sich.In der Schule unterrichten sie normalerweise den i ++ Weg, aber es gibt auch viele Leute, die den ++ i Weg aus mehreren Gründen bevorzugen .
HINWEIS: In der Vergangenheit hat i ++ nur sehr geringe Auswirkungen auf die Leistung, da es nicht nur eins für sich plus, sondern auch den ursprünglichen Wert im Register behält. Im Moment macht es jedoch keinen Unterschied, da der Compiler das Plus-Teil gleich macht.
Bei Schleifen kann es einen Unterschied geben. Dies ist die praktische Anwendung von Post / Pre-Inkrement.
int i = 0;
while(i++ <= 10) {
Console.Write(i);
}
Console.Write(System.Environment.NewLine);
i = 0;
while(++i <= 10) {
Console.Write(i);
}
Console.ReadLine();
Während der erste bis 11 zählt und 11-mal schleift, tut der zweite nicht.
Meistens wird dies eher in einer einfachen Weile verwendet (x--> 0); - - Schleife, um zum Beispiel alle Elemente eines Arrays zu iterieren (ausgenommen hier foreach-Konstrukte).
Beide erhöhen die Zahl. ++i
ist äquivalent zu i = i + 1
.
i++
und ++i
sind sehr ähnlich, aber nicht genau gleich. Beide erhöhen die Zahl, ++i
erhöhen jedoch die Zahl, bevor der aktuelle Ausdruck ausgewertet wirdi++
die Zahl erhöht wird, nachdem der Ausdruck ausgewertet wurde.
int i = 3;
int a = i++; // a = 3, i = 4
int b = ++a; // b = 4, a =
Überprüfen Sie diesen Link .
Ja, es gibt einen Unterschied zwischen ++i
und i++
in einer for
Schleife, wenn auch in ungewöhnlichen Anwendungsfällen. wenn eine Schleifenvariable mit Inkrement / Dekrement-Operator im for-Block oder innerhalb des Schleifentestausdrucks oder mit einer der Schleifenvariablen verwendet wird . Nein, es ist nicht einfach eine Syntaxsache.
Wie i
in einem Code bedeutet das Auswerten des Ausdrucks i
und der Operator bedeutet nicht eine Auswertung, sondern nur eine Operation;
++i
bedeutet Inkrementwert i
von 1 und später auswerteni
,i++
bedeutet auswerten i
und später den Wert i
um 1 erhöhen .Was also aus jeweils zwei Ausdrücken erhalten wird, unterscheidet sich, weil das, was ausgewertet wird, in jedem unterschiedlich ist. Alles gleich für--i
undi--
Beispielsweise;
let i = 0
i++ // evaluates to value of i, means evaluates to 0, later increments i by 1, i is now 1
0
i
1
++i // increments i by 1, i is now 2, later evaluates to value of i, means evaluates to 2
2
i
2
In ungewöhnlichen Anwendungsfällen ist das nächste Beispiel zwar nützlich oder nicht wichtig, es zeigt jedoch einen Unterschied
for(i=0, j=i; i<10; j=++i){
console.log(j, i)
}
for(i=0, j=i; i<10; j=i++){
console.log(j, i)
}
Für i
benutzerdefinierte Typen könnten ( sollten aber nicht ) diese Operatoren im Kontext eines Schleifenindex signifikant unterschiedliche Sematiken haben, und dies könnte (sollte aber nicht) das Verhalten der beschriebenen Schleife beeinflussen.
Außerdem ist c++
es im Allgemeinen am sichersten, das Pre-Inkrement-Formular ( ++i
) zu verwenden, da es einfacher zu optimieren ist. (Scott Langham hat mich zu diesem Leckerbissen geschlagen . Verfluche dich, Scott)
Ich weiß es nicht für die anderen Sprachen, aber in Java ++ ist i ein Präfixinkrement, was bedeutet: Erhöhe i um 1 und verwende dann den neuen Wert von i in dem Ausdruck, in dem ich mich befinde , und i ++ ist ein Postfixinkrement , das Folgendes bedeutet : Verwenden Sie den aktuellen Wert von i im Ausdruck und erhöhen Sie ihn dann um 1. Beispiel:
public static void main(String [] args){
int a = 3;
int b = 5;
System.out.println(++a);
System.out.println(b++);
System.out.println(b);
} und die Ausgabe ist: