C'è una differenza in ++i
e i++
in un for
ciclo? È semplicemente una cosa di sintassi?
C'è una differenza in ++i
e i++
in un for
ciclo? È semplicemente una cosa di sintassi?
Risposte:
a ++ è noto come postfix.
aggiungi 1 a a, restituisce il vecchio valore.
++ a è noto come prefisso.
aggiungi 1 a a, restituisce il nuovo valore.
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++);
}
Produzione:
1
2
3
4
0
1
2
3
foreach
e i while
loop dipendono dal tipo di incremento utilizzato. Con per i loop come sotto non fa alcuna differenza poiché non stai usando il valore di ritorno di i:
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
Se viene utilizzato il valore valutato, il tipo di incremento diventa significativo:
int n = 0;
for (int i = 0; n < 5; n = i++) { }
Pre-incremento ++ i incrementa il valore di i e restituisce il nuovo valore incrementato.
int i = 3;
int preIncrementResult = ++i;
Assert( preIncrementResult == 4 );
Assert( i == 4 );
Post-increment i ++ incrementa il valore di i e restituisce il valore originale non incrementato.
int i = 3;
int postIncrementResult = i++;
Assert( postIncrementtResult == 3 );
Assert( i == 4 );
In C ++, il pre-incremento è di solito preferito dove è possibile utilizzare entrambi.
Questo perché se si utilizza post-incremento, può essere necessario che il compilatore debba generare codice che crea una variabile temporanea aggiuntiva. Questo perché sia il valore precedente che quello nuovo della variabile da incrementare devono essere mantenuti da qualche parte perché potrebbero essere necessari altrove nell'espressione da valutare.
Quindi, almeno in C ++, può esserci una differenza di prestazioni che guida la tua scelta di quale utilizzare.
Questo è principalmente un problema solo quando la variabile da incrementare è un tipo definito dall'utente con un operatore ++ ignorato. Per i tipi primitivi (int, ecc.) Non c'è differenza di prestazioni. Ma vale la pena attenersi all'operatore di pre-incremento come linea guida a meno che l'operatore di post-incremento sia sicuramente ciò che è richiesto.
C'è ancora qualche discussione qui:
https://web.archive.org/web/20170405054235/http://en.allexperts.com/q/C-1040/Increment-operators.htm
In C ++ se si utilizza STL, è possibile che si utilizzi per loop con iteratori. Questi hanno principalmente override ++ operatori, quindi attenersi al pre-incremento è una buona idea. I compilatori diventano sempre più intelligenti, e quelli più recenti potrebbero essere in grado di eseguire ottimizzazioni che significano che non ci sono differenze di prestazioni - specialmente se il tipo da incrementare è definito in linea nel file di intestazione (come spesso lo sono le implementazioni STL) in modo che il compilatore possa vedere come il metodo è implementato e può quindi sapere quali ottimizzazioni sono sicure da eseguire. Anche così, probabilmente vale comunque la pena attenersi al pre-incremento perché i loop vengono eseguiti molte volte e questo significa che una piccola penalità prestazionale potrebbe presto essere amplificata.
In altri linguaggi come C # in cui l'operatore ++ non può essere sovraccaricato, non vi sono differenze di prestazioni. Utilizzati in un ciclo per far avanzare la variabile del ciclo, gli operatori pre e post incremento sono equivalenti.
Correzione: è consentito l'overloading ++ in C #. Sembra però che, rispetto a C ++, in c # non sia possibile sovraccaricare le versioni pre e post in modo indipendente. Quindi, suppongo che se il risultato della chiamata ++ in C # non è assegnato a una variabile o utilizzato come parte di un'espressione complessa, il compilatore ridurrebbe le versioni pre e post di ++ fino al codice che funziona in modo equivalente.
In C # non c'è differenza se usato in un ciclo for .
for (int i = 0; i < 10; i++) { Console.WriteLine(i); }
produce la stessa cosa di
for (int i = 0; i < 10; ++i) { Console.WriteLine(i); }
Come altri hanno sottolineato, quando usato in generale i ++ e ++ ho una differenza sottile ma significativa:
int i = 0;
Console.WriteLine(i++); // Prints 0
int j = 0;
Console.WriteLine(++j); // Prints 1
i ++ legge il valore di i quindi lo incrementa.
++ I incrementa il valore di i quindi lo legge.
++i
ed i++
eseguono le stesse operazioni nello stesso ordine: create una copia temporanea di i
; incrementare il valore temporaneo per produrre un nuovo valore (non sovrascrivere il temp); memorizzare il nuovo valore in i
; ora se è ++i
il risultato restituito è il nuovo valore; se è i++
il risultato restituito è la copia temporanea. Più dettagliato risposta qui: stackoverflow.com/a/3346729/3330348
La domanda è:
C'è una differenza tra ++ ie i ++ in un ciclo for?
La risposta è: no .
Perché ogni altra risposta deve andare in spiegazioni dettagliate sull'incremento pre e post quando questo non viene nemmeno chiesto?
Questo for-loop:
for (int i = 0; // Initialization
i < 5; // Condition
i++) // Increment
{
Output(i);
}
Si tradurrebbe in questo codice senza usare i loop:
int i = 0; // Initialization
loopStart:
if (i < 5) // Condition
{
Output(i);
i++ or ++i; // Increment
goto loopStart;
}
Ora importa se metti i++
o ++i
come incremento qui? No, poiché il valore restituito dall'operazione di incremento è insignificante. i
verrà incrementato DOPO l'esecuzione del codice all'interno del corpo del ciclo for.
Dal momento che chiedi della differenza in un ciclo, immagino che intendi
for(int i=0; i<10; i++)
...;
In tal caso, non hai differenze nella maggior parte delle lingue: il ciclo si comporta allo stesso modo indipendentemente dal fatto che tu scriva i++
e ++i
. In C ++, puoi scrivere le tue versioni degli operatori ++ e puoi definire significati separati per loro, se i
è di tipo definito dall'utente (la tua classe, per esempio).
Il motivo per cui non importa sopra è perché non usi il valore di i++
. Un'altra cosa è quando lo fai
for(int i=0, a = 0; i<10; a = i++)
...;
Ora, c'è una differenza, perché, come altri sottolineano, i++
mezzi incrementano, ma restituiscono il valore precedente , ma ++i
mezzi incremento, ma valutata comei
(quindi sarebbe valutare il nuovo valore). Nel caso precedente, a
viene assegnato il valore precedente di i, mentre i viene incrementato.
Come mostra questo codice (vedere MSIL disordinato nei commenti), il compilatore C # 3 non fa distinzione tra i ++ e ++ i in un ciclo for. Se il valore di i ++ o ++ i venisse preso, ci sarebbe sicuramente una differenza (questo è stato compilato in Visutal Studio 2008 / Release Build):
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++;
}
}
}
}
Uno (++ i) è preincrement, uno (i ++) è postincrement. La differenza sta nel valore immediatamente restituito dall'espressione.
// Psuedocode
int i = 0;
print i++; // Prints 0
print i; // Prints 1
int j = 0;
print ++j; // Prints 1
print j; // Prints 1
Modifica: Woops, ha completamente ignorato il lato loop delle cose. Non esiste alcuna differenza effettiva per i loop quando si tratta della parte 'step' (per (...; ...;)), ma può entrare in gioco in altri casi.
Non vi è alcuna differenza se non si utilizza il valore dopo l'incremento nel ciclo.
for (int i = 0; i < 4; ++i){
cout<<i;
}
for (int i = 0; i < 4; i++){
cout<<i;
}
Entrambi i loop stamperanno 0123.
Ma la differenza viene quando si utilizza il valore dopo l'incremento / decremento nel proprio loop come di seguito:
Ciclo pre-incremento:
for (int i = 0,k=0; i < 4; k=++i){
cout<<i<<" ";
cout<<k<<" ";
}
Uscita: 0 0 1 1 2 2 3 3
Ciclo post-incremento:
for (int i = 0, k=0; i < 4; k=i++){
cout<<i<<" ";
cout<<k<<" ";
}
Uscita: 0 0 1 0 2 1 3 2
Spero che la differenza sia chiara confrontando l'output. Da notare qui che l'incremento / decremento viene sempre eseguito alla fine del ciclo for e quindi i risultati possono essere spiegati.
Ecco un esempio Java e il codice byte, post e preIncrement non mostrano alcuna differenza in 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;
}
}
}
E ora per il codice byte (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
}
Si C'è. La differenza sta nel valore restituito. Il valore di ritorno di "++ i" sarà il valore dopo aver incrementato i. Il ritorno di "i ++" sarà il valore prima dell'incremento. Ciò significa che il codice è simile al seguente:
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.
Pertanto, a sarebbe 2 e bec sarebbe ciascuno 1.
Potrei riscrivere il codice in questo modo:
int a = 0;
// ++a;
a = a + 1; // incrementing first.
b = a; // setting second.
// a++;
c = a; // setting first.
a = a + 1; // incrementing second.
Non vi è alcuna differenza effettiva in entrambi i casi ' i
' verrà incrementato di 1.
Ma c'è una differenza quando lo usi in un'espressione, ad esempio:
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
C'è più di ++ i e i ++ di loop e differenze di prestazioni. ++ i restituisce un valore l e i ++ restituisce un valore r. Sulla base di questo, ci sono molte cose che puoi fare per (++ i) ma non per (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;
}
Mi confonde il motivo per cui così le persone possono scrivere l'espressione di incremento in for-loop come i ++.
In un ciclo for, quando il 3o componente è una semplice istruzione di incremento, come in
for (i=0; i<x; i++)
o
for (i=0; i<x; ++i)
non vi è alcuna differenza nelle esecuzioni risultanti.
Come dice @Jon B , non c'è differenza in un ciclo for.
Ma in un ciclo while
o do...while
, potresti trovare alcune differenze se stai facendo un confronto con il ++i
oi++
while(i++ < 10) { ... } //compare then increment
while(++i < 10) { ... } //increment then compare
In javascript a causa del seguente i ++ potrebbe essere meglio usare:
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.
Mentre gli array (penso tutto) e alcune altre funzioni e chiamate usano 0 come punto di partenza, dovresti impostare i su -1 per far funzionare il loop con l'array quando usi ++ i .
Quando si utilizza i ++, il valore seguente utilizzerà il valore aumentato. Potresti dire che i ++ è il modo in cui gli umani contano, perché puoi iniziare con uno 0 .
Per capire cosa fa un ciclo FOR
L'immagine sopra mostra che FOR può essere convertito in WHILE , poiché alla fine hanno totalmente lo stesso codice assembly (almeno in gcc). Quindi possiamo scomporre FOR in un paio di pezzi, per capire cosa fa.
for (i = 0; i < 5; ++i) {
DoSomethingA();
DoSomethingB();
}
è uguale alla versione WHILE
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
}
Significa che puoi usare FOR come semplice versione di WHILE :
Il primo argomento di FOR (int i) viene eseguito, all'esterno, prima del ciclo.
Il terzo argomento di FOR (i ++ o ++ i) viene eseguito, all'interno, nell'ultima riga del ciclo.
TL: DR: indipendentemente dal fatto
i++
che++i
, sappiamo che quando sono autonomi, non fanno differenza ma +1 su se stessi.A scuola di solito insegnano alla maniera i ++, ma ci sono anche molte persone che preferiscono la via ++ i per diversi motivi .
NOTA: In passato, i ++ ha un impatto molto limitato sulle prestazioni, poiché non solo ne aumenta una da sola, ma mantiene anche il valore originale nel registro. Ma per ora, non fa alcuna differenza poiché il compilatore rende il plus una parte uguale.
Può esserci una differenza per i loop. Questa è l'applicazione pratica di post / pre-incremento.
int i = 0;
while(i++ <= 10) {
Console.Write(i);
}
Console.Write(System.Environment.NewLine);
i = 0;
while(++i <= 10) {
Console.Write(i);
}
Console.ReadLine();
Mentre il primo conta fino a 11 e scorre 11 volte, il secondo no.
Principalmente questo è piuttosto usato in un po 'di tempo (x--> 0); - - Loop per iterare ad esempio tutti gli elementi di un array (esentando foreach-build qui).
Entrambi incrementano il numero. ++i
è equivalente a i = i + 1
.
i++
e ++i
sono molto simili ma non esattamente uguali. Entrambi incrementano il numero, ma ++i
incrementa il numero prima che venga valutata l'espressione corrente, mentre i++
incrementa il numero dopo la valutazione dell'espressione.
int i = 3;
int a = i++; // a = 3, i = 4
int b = ++a; // b = 4, a =
Controllare questo link .
Sì, c'è una differenza tra ++i
e i++
in un for
ciclo, sebbene in casi d'uso insoliti; quando una variabile di loop con operatore di incremento / decremento viene utilizzata nel blocco for o nell'espressione di test del loop o con una delle variabili di loop . No, non è semplicemente una cosa di sintassi.
Come i
in un codice significa valutare l'espressione i
e l'operatore non significa una valutazione ma solo un'operazione;
++i
significa incrementare il valore di i
1 e successivamente valutare i
,i++
significa valutare i
e successivamente incrementare il valore di i
1.Quindi, ciò che si ottiene da ciascuna delle due espressioni differisce perché ciò che viene valutato differisce in ciascuna. Tutti uguali per --i
ei--
Per esempio;
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 casi d'uso insoliti, tuttavia il prossimo esempio sembra utile o non importa, mostra una differenza
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)
}
Per i
i tipi definiti dall'utente, questi operatori potrebbero (ma non dovrebbero ) avere una semantica significativamente diversa nel contesto di un indice di loop e questo potrebbe (ma non dovrebbe) influenzare il comportamento del loop descritto.
Inoltre, c++
è generalmente più sicuro utilizzare il modulo di pre-incremento ( ++i
) perché è più facilmente ottimizzato. (Scott Langham mi ha battuto su questo bocconcino . Maledizione, Scott)
Non so per le altre lingue, ma in Java ++ i è un prefisso di incremento , che significa: aumentare i di 1 e quindi utilizzare il nuovo valore dei nell'espressione in cui i risiede, ed i ++ è un incremento di suffisso che significa che il seguente : usa il valore corrente di i nell'espressione e poi aumentalo di 1. Esempio:
public static void main(String [] args){
int a = 3;
int b = 5;
System.out.println(++a);
System.out.println(b++);
System.out.println(b);
} e l'output è: