Y a-t-il une différence dans ++i
et i++
dans une for
boucle? Est-ce simplement une question de syntaxe?
Y a-t-il une différence dans ++i
et i++
dans une for
boucle? Est-ce simplement une question de syntaxe?
Réponses:
a ++ est appelé postfix.
ajouter 1 à a, renvoie l'ancienne valeur.
++ a est appelé préfixe.
ajouter 1 à a, renvoie la nouvelle valeur.
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++);
}
Production:
1
2
3
4
0
1
2
3
foreach
et les while
boucles dépendent du type d'incrément que vous utilisez. Avec des boucles for comme ci-dessous, cela ne fait aucune différence car vous n'utilisez pas la valeur de retour de 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
Si la valeur évaluée est utilisée, le type d'incrément devient significatif:
int n = 0;
for (int i = 0; n < 5; n = i++) { }
Pre-increment ++ i incrémente la valeur de i et évalue la nouvelle valeur incrémentée.
int i = 3;
int preIncrementResult = ++i;
Assert( preIncrementResult == 4 );
Assert( i == 4 );
Post-increment i ++ incrémente la valeur de i et évalue la valeur d'origine non incrémentée.
int i = 3;
int postIncrementResult = i++;
Assert( postIncrementtResult == 3 );
Assert( i == 4 );
En C ++, la pré-incrémentation est généralement préférée lorsque vous pouvez utiliser l'une ou l'autre.
En effet, si vous utilisez la post-incrémentation, le compilateur peut avoir à générer du code qui crée une variable temporaire supplémentaire. Cela est dû au fait que les valeurs précédentes et nouvelles de la variable incrémentée doivent être conservées quelque part, car elles peuvent être nécessaires ailleurs dans l'expression à évaluer.
Ainsi, en C ++ au moins, il peut y avoir une différence de performances qui guide votre choix de celui à utiliser.
Il s'agit principalement d'un problème uniquement lorsque la variable incrémentée est un type défini par l'utilisateur avec un opérateur ++ remplacé. Pour les types primitifs (int, etc.), il n'y a pas de différence de performances. Mais, cela vaut la peine de s'en tenir à l'opérateur de pré-incrémentation à titre indicatif, sauf si l'opérateur de post-incrémentation est définitivement ce qui est requis.
Il y a plus de discussion ici:
https://web.archive.org/web/20170405054235/http://en.allexperts.com/q/C-1040/Increment-operators.htm
En C ++ si vous utilisez STL, vous utilisez peut-être des boucles avec des itérateurs. Ceux-ci ont principalement des opérateurs ++ remplacés, donc s'en tenir à la pré-incrémentation est une bonne idée. Les compilateurs deviennent toujours plus intelligents, et les plus récents peuvent être en mesure d'effectuer des optimisations qui signifient qu'il n'y a pas de différence de performances - en particulier si le type incrémenté est défini en ligne dans le fichier d'en-tête (comme le sont souvent les implémentations STL) afin que le compilateur puisse voir comment la méthode est implémentée et peut alors savoir quelles optimisations sont sûres à effectuer. Néanmoins, cela vaut probablement la peine de s'en tenir à la pré-incrémentation, car les boucles sont exécutées de nombreuses fois et cela signifie qu'une petite pénalité de performance pourrait bientôt être amplifiée.
Dans d'autres langages tels que C # où l'opérateur ++ ne peut pas être surchargé, il n'y a pas de différence de performances. Utilisés dans une boucle pour faire avancer la variable de boucle, les opérateurs pré et post-incrémentation sont équivalents.
Correction: la surcharge ++ en C # est autorisée. Il semble cependant que, par rapport à C ++, en c #, vous ne pouvez pas surcharger les versions pré et post indépendamment. Donc, je suppose que si le résultat de l'appel de ++ en C # n'est pas affecté à une variable ou utilisé dans le cadre d'une expression complexe, le compilateur réduira les versions pré et post de ++ vers du code qui fonctionne de manière équivalente.
En C #, il n'y a pas de différence lorsqu'il est utilisé dans une boucle for .
for (int i = 0; i < 10; i++) { Console.WriteLine(i); }
sort la même chose que
for (int i = 0; i < 10; ++i) { Console.WriteLine(i); }
Comme d'autres l'ont souligné, lorsqu'ils sont utilisés en général i ++ et ++, j'ai une différence subtile mais significative:
int i = 0;
Console.WriteLine(i++); // Prints 0
int j = 0;
Console.WriteLine(++j); // Prints 1
i ++ lit la valeur de i puis l'incrémente.
++ i incrémente la valeur de i puis la lit.
++i
et i++
exécutent les mêmes opérations dans le même ordre: créer une copie temporaire de i
; incrémentez la valeur de temp pour produire une nouvelle valeur (pour ne pas remplacer la temp); stocker la nouvelle valeur dans i
; maintenant, si c'est ++i
le résultat renvoyé, c'est la nouvelle valeur; si c'est i++
le résultat retourné, c'est la copie temporaire. Réponse plus détaillée ici: stackoverflow.com/a/3346729/3330348
La question est:
Y a-t-il une différence entre ++ i et i ++ dans une boucle for?
La réponse est: non .
Pourquoi chaque réponse doit-elle entrer dans des explications détaillées sur la pré et post-incrémentation alors que ce n'est même pas demandé?
Cette boucle for:
for (int i = 0; // Initialization
i < 5; // Condition
i++) // Increment
{
Output(i);
}
Se traduirait dans ce code sans utiliser de boucles:
int i = 0; // Initialization
loopStart:
if (i < 5) // Condition
{
Output(i);
i++ or ++i; // Increment
goto loopStart;
}
Maintenant, est-ce important si vous mettez i++
ou ++i
comme incrément ici? Non, ce n'est pas le cas car la valeur de retour de l'opération d'incrémentation est insignifiante. i
sera incrémenté APRÈS l'exécution du code qui se trouve dans le corps de la boucle for.
Puisque vous demandez la différence dans une boucle, je suppose que vous voulez dire
for(int i=0; i<10; i++)
...;
Dans ce cas, vous n'avez aucune différence dans la plupart des langues: la boucle se comporte de la même manière, que vous écriviez i++
ou non ++i
. En C ++, vous pouvez écrire vos propres versions des opérateurs ++, et vous pouvez définir des significations distinctes pour eux, si le i
est d'un type défini par l'utilisateur (votre propre classe, par exemple).
La raison pour laquelle cela n'a pas d'importance ci-dessus est que vous n'utilisez pas la valeur de i++
. Une autre chose est quand vous faites
for(int i=0, a = 0; i<10; a = i++)
...;
Maintenant, il y a une différence, car comme d'autres le font remarquer, i++
signifie incrémenter, mais évaluer à la valeur précédente , mais ++i
signifie incrémenter, mais évaluer ài
(donc il évaluerait à la nouvelle valeur). Dans le cas ci-dessus, a
la valeur précédente de i est affectée, tandis que i est incrémenté.
Comme le montre ce code (voir le MSIL dissambled dans les commentaires), le compilateur C # 3 ne fait aucune distinction entre i ++ et ++ i dans une boucle for. Si la valeur de i ++ ou ++ i était prise, il y aurait certainement une différence (cela a été compilé dans 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++;
}
}
}
}
Un (++ i) est pré-incrémenté, un (i ++) est post-incrémenté. La différence réside dans la valeur immédiatement renvoyée par l'expression.
// 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, complètement ignoré le côté boucle des choses. Il n'y a pas de réelle différence dans les boucles for lorsqu'il s'agit de la partie 'step' (pour (...; ...;)), mais cela peut entrer en jeu dans d'autres cas.
Il n'y a aucune différence si vous n'utilisez pas la valeur après incrément dans la boucle.
for (int i = 0; i < 4; ++i){
cout<<i;
}
for (int i = 0; i < 4; i++){
cout<<i;
}
Les deux boucles imprimeront 0123.
Mais la différence survient lorsque vous utilisez la valeur après incrément / décrément dans votre boucle comme ci-dessous:
Boucle de pré-incrémentation:
for (int i = 0,k=0; i < 4; k=++i){
cout<<i<<" ";
cout<<k<<" ";
}
Sortie: 0 0 1 1 2 2 3 3
Boucle de post-incrémentation:
for (int i = 0, k=0; i < 4; k=i++){
cout<<i<<" ";
cout<<k<<" ";
}
Sortie: 0 0 1 0 2 1 3 2
J'espère que la différence est claire en comparant la sortie. Le point à noter ici est que l'incrémentation / décrémentation est toujours effectuée à la fin de la boucle for et donc les résultats peuvent être expliqués.
Voici un exemple Java et le Byte-Code, le post et le pré-incrément ne montrent aucune différence dans le 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;
}
}
}
Et maintenant pour le code d'octet (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
}
Oui il y a. La différence réside dans la valeur de retour. La valeur de retour de "++ i" sera la valeur après l' incrémentation de i. Le retour de "i ++" sera la valeur avant l' incrémentation. Cela signifie que le code qui ressemble à ceci:
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.
Par conséquent, a serait 2 et b et c seraient chacun 1.
Je pourrais réécrire le code comme ceci:
int a = 0;
// ++a;
a = a + 1; // incrementing first.
b = a; // setting second.
// a++;
c = a; // setting first.
a = a + 1; // incrementing second.
Il n'y a pas de différence réelle dans les deux cas ' i
' sera incrémenté de 1.
Mais il y a une différence lorsque vous l'utilisez dans une expression, par exemple:
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
Il y a plus à ++ i et i ++ que des boucles et des différences de performances. ++ i renvoie une valeur l et i ++ renvoie une valeur r. Sur cette base, il y a beaucoup de choses que vous pouvez faire pour (++ i) mais pas pour (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;
}
Cela m'embarrasse de savoir pourquoi les gens peuvent écrire l'expression d'incrémentation en boucle for comme i ++.
Dans une boucle for, lorsque le 3e composant est une simple instruction d'incrémentation, comme dans
for (i=0; i<x; i++)
ou
for (i=0; i<x; ++i)
il n'y a aucune différence dans les exécutions qui en résultent.
Comme le dit @Jon B , il n'y a pas de différence dans une boucle for.
Mais dans une boucle while
ou do...while
, vous pouvez trouver des différences si vous faites une comparaison avec le ++i
oui++
while(i++ < 10) { ... } //compare then increment
while(++i < 10) { ... } //increment then compare
En javascript en raison des éléments suivants, il est préférable d'utiliser i ++:
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.
Alors que les tableaux (je pense que tous) et certaines autres fonctions et appels utilisent 0 comme point de départ, vous devez définir i sur -1 pour faire fonctionner la boucle avec le tableau lorsque vous utilisez ++ i .
Lorsque vous utilisez i ++, la valeur suivante utilise la valeur augmentée. On pourrait dire que i ++ est la façon dont les humains comptent, car vous pouvez commencer avec un 0 .
Pour comprendre ce que fait une boucle FOR
L'image ci-dessus montre que FOR peut être converti en WHILE , car ils ont finalement totalement le même code assembleur (au moins dans gcc). Nous pouvons donc décomposer FOR en quelques morceaux, pour comprendre ce qu'il fait.
for (i = 0; i < 5; ++i) {
DoSomethingA();
DoSomethingB();
}
est égal à la version 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
}
Cela signifie que vous pouvez utiliser FOR comme une version simple de WHILE :
Le premier argument de FOR (int i) est exécuté, à l'extérieur, avant la boucle.
Le troisième argument de FOR (i ++ ou ++ i) est exécuté, à l'intérieur, dans la dernière ligne de la boucle.
TL: DR: peu importe si
i++
ou++i
, nous savons que quand ils sont autonomes, ils ne font aucune différence , mais +1 sur eux - mêmes.À l'école, ils enseignent généralement la méthode i ++, mais il y a aussi beaucoup de gens qui préfèrent la méthode ++ i pour plusieurs raisons .
REMARQUE: dans le passé, i ++ a très peu d'impact sur les performances, car il n'a pas seulement plus un seul, mais conserve également la valeur d'origine dans le registre. Mais pour l'instant, cela ne fait aucune différence car le compilateur rend la partie positive identique.
Il peut y avoir une différence pour les boucles. Il s'agit de l'application pratique du post / pré-incrément.
int i = 0;
while(i++ <= 10) {
Console.Write(i);
}
Console.Write(System.Environment.NewLine);
i = 0;
while(++i <= 10) {
Console.Write(i);
}
Console.ReadLine();
Alors que le premier compte jusqu'à 11 et boucle 11 fois, le second non.
Généralement, cela est plutôt utilisé dans un temps simple (x--> 0); - - Boucle pour itérer par exemple tous les éléments d'un tableau (en excluant foreach-constructs ici).
Ils incrémentent tous les deux le nombre. ++i
est équivalent à i = i + 1
.
i++
et ++i
sont très similaires mais pas exactement les mêmes. Les deux incrémentent le nombre, mais ++i
incrémentent le nombre avant que l'expression actuelle ne soit évaluée, tandis que l' i++
incrémente le nombre après que l'expression est évaluée.
int i = 3;
int a = i++; // a = 3, i = 4
int b = ++a; // b = 4, a =
Vérifiez ce lien .
Oui, il y a une différence entre ++i
et i++
dans une for
boucle, bien que dans des cas d'utilisation inhabituels; lorsqu'une variable de boucle avec opérateur d'incrémentation / décrémentation est utilisée dans le bloc for ou dans l'expression de test de boucle , ou avec l'une des variables de boucle . Non, ce n'est pas simplement une chose de syntaxe.
Comme i
dans un code signifie évaluer l'expression i
et l'opérateur ne signifie pas une évaluation mais juste une opération;
++i
signifie incrémenter la valeur de i
1 et évaluer plus tard i
,i++
signifie évaluer i
et incrémenter ultérieurement la valeur de i
1.Ainsi, ce qui est obtenu à partir de chacune des deux expressions diffère parce que ce qui est évalué diffère dans chacune. Même chose pour --i
eti--
Par exemple;
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
Dans des cas d'utilisation inhabituels, cependant l'exemple suivant semble utile ou non, cela montre une différence
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)
}
Pour i
les types définis par l'utilisateur, ces opérateurs pourraient (mais ne devraient pas ) avoir une sémantique significativement différente dans le contexte d'un index de boucle, ce qui pourrait (mais ne devrait pas) affecter le comportement de la boucle décrite.
De plus, c++
il est généralement plus sûr d'utiliser le formulaire de pré-incrémentation ( ++i
) car il est plus facilement optimisé. (Scott Langham m'a battu à cette friandise . Je vous maudis , Scott)
Je ne sais pas pour les autres langages mais en Java ++ i est un incrément de préfixe qui signifie: augmenter i de 1 puis utiliser la nouvelle valeur de i dans l'expression dans laquelle je réside, et i ++ est un incrément postfix qui signifie ce qui suit : utilisez la valeur actuelle de i dans l'expression, puis augmentez-la de 1. Exemple:
public static void main(String [] args){
int a = 3;
int b = 5;
System.out.println(++a);
System.out.println(b++);
System.out.println(b);
} et la sortie est: