C: Quelle est la différence entre ++ i et i ++?


889

En C, quelle est la différence entre l'utilisation de ++iet i++, et laquelle doit être utilisée dans le bloc d'incrémentation d'une forboucle?


10
Pas sûr que l'affiche originale soit intéressée, mais en C ++, la différence de performances peut être substantielle, car la création de l'objet temporaire peut être coûteuse pour un type défini par l'utilisateur.
Le

Réponses:


1101
  • ++iincrémentera la valeur de i, puis renverra la valeur incrémentée.

     i = 1;
     j = ++i;
     (i is 2, j is 2)
  • i++incrémentera la valeur de i, mais renverra la valeur d'origine qui icontenait avant d'être incrémentée.

     i = 1;
     j = i++;
     (i is 2, j is 1)

Pour une forboucle, l'un ou l'autre fonctionne. ++isemble plus courant, peut-être parce que c'est ce qui est utilisé dans K&R .

Dans tous les cas, suivez la directive "préférez ++iplutôt i++" et vous ne vous tromperez pas.

Il y a quelques commentaires concernant l'efficacité de ++iet i++. Dans tout compilateur non étudiant-projet, il n'y aura aucune différence de performance. Vous pouvez le vérifier en regardant le code généré, qui sera identique.

La question de l'efficacité est intéressante ... voici ma tentative de réponse: y a-t-il une différence de performances entre i ++ et ++ i en C?

Comme le note @OnFreund , c'est différent pour un objet C ++, car il operator++()s'agit d'une fonction et le compilateur ne peut pas savoir optimiser la création d'un objet temporaire pour contenir la valeur intermédiaire.


6
Cet effet ne résiste-t-il pas à la répétition de la boucle une fois la condition finale atteinte? Par exemple, for(int i=0; i<10; i++){ print i; } cela ne sera-t-il pas différent de for(int i=0; i<10; ++i){ print i; } Ma compréhension est que certaines langues vous donneront des résultats différents en fonction de celui que vous utilisez.
aVeRTRAC

27
jonnyflash, les deux fonctionneront de manière identique, car l'incrément de i et l'impression sont dans des instructions différentes. Cela devrait être le cas pour tout langage prenant en charge C-style ++. La seule différence entre ++ i et i ++ sera lors de l'utilisation de la valeur de l'opération dans la même instruction.
Mark Harrison

16
Étant donné que dans la plupart des cas, ils produisent un code identique, je préfère i++car il est de la forme "opérande-opérateur", à la manière d'une "opérande-opérateur-valeur". En d'autres termes, l'opérande cible est sur le côté gauche de l'expression, tout comme dans une instruction d'affectation.
David R Tribble

2
@MarkHarrison, il fonctionnera à l'identique non pas parce que i++et print isont dans des déclarations différentes, mais parce que i++;et i<10sont. La remarque de @ jonnyflash n'est pas que hors de la base. Supposons que vous ayez for(int i=0; i++<10){ print i; }et for(int i=0; ++i<10){ print i; }. Ceux-ci fonctionneront différemment de la manière décrite par @johnnyflash dans le premier commentaire.
Adam

3
@sam, car dans une boucle for typique, il n'y a pas d'effet secondaire (par exemple, affectation) dans la partie ++ i.
Mark Harrison

175

i ++ est connu comme Post Increment tandis que ++ i est appelé Pre Increment.

i++

i++est post-incrément car il incrémente ila valeur de 1 après la fin de l'opération.

Voyons l'exemple suivant:

int i = 1, j;
j = i++;

Voici la valeur de j = 1mais i = 2. Ici, la valeur de isera affectée à jfirst puis isera incrémentée.

++i

++iest pré-incrémenté car il incrémente ila valeur de 1 avant l'opération. Cela signifie j = i;s'exécutera après i++.

Voyons l'exemple suivant:

int i = 1, j;
j = ++i;

Voici la valeur de j = 2mais i = 2. Ici, la valeur de isera affectée à japrès l' i incrémentation de i. De même ++isera exécuté avant j=i;.

Pour votre question qui devrait être utilisé dans le bloc d'incrémentation d'une boucle for? la réponse est, vous pouvez utiliser n'importe qui .. n'a pas d'importance. Il exécutera votre boucle for no. de fois.

for(i=0; i<5; i++)
   printf("%d ",i);

Et

for(i=0; i<5; ++i)
   printf("%d ",i);

Les deux boucles produiront la même sortie. ie 0 1 2 3 4.

Peu importe où vous l'utilisez.

for(i = 0; i<5;)
    printf("%d ",++i);

Dans ce cas, la sortie sera 1 2 3 4 5.


1
L'initialisation des variables après le préfixe et le post-fix aide à comprendre. Merci.
Abdul Alim Shakir le

42

Veuillez ne pas vous soucier de l '"efficacité" (vitesse, vraiment) dont l'une est plus rapide. Nous avons des compilateurs de nos jours qui s'occupent de ces choses. Utilisez celui qui est le plus judicieux à utiliser, en fonction de celui qui montre plus clairement votre intention.


1
ce qui, je l'espère, signifie ' utiliser le préfixe (inc | dec) à moins que vous n'ayez réellement besoin de l'ancienne valeur avant le (inc | dec), ce que très peu de gens font, et pourtant qu'une proportion déroutante du matériel pédagogique supposé utilise, créer un culte du fret d'utilisateurs postfix qui ne savent même pas ce que c'est '..!
underscore_d

Je ne suis pas sûr que «les compilateurs de nos jours ... s'occupent de ces choses» soit universellement vrai. Dans une version personnalisée operator++(int)(la version postfix), le code doit à peu près créer un temporaire qui sera retourné. Êtes-vous sûr que les compilateurs peuvent toujours optimiser cela?
Peter - Réintègre Monica

36

++i incrémente la valeur, puis la renvoie.

i++ renvoie la valeur, puis l'incrémente.

C'est une subtile différence.

Pour une boucle for, utilisez ++i, car c'est un peu plus rapide. i++créera une copie supplémentaire qui sera simplement jetée.


23
Je ne connais aucun compilateur où cela fait au moins une différence pour les entiers.
blabla999

4
Ce n'est pas plus rapide . Les valeurs sont ignorées (seul l'effet secondaire est efficace) et le compilateur peut / générera exactement le même code.
Wildplasser

31

i++: Dans ce scénario, la valeur est d'abord attribuée, puis l'incrémentation se produit.

++i: Dans ce scénario, l'incrémentation est d'abord effectuée, puis la valeur est affectée

Ci-dessous est la visualisation de l'image et voici également une belle vidéo pratique qui démontre la même chose.

entrez la description de l'image ici


Comment pouvez-vous incrémenter quelque peu non attribué?
kouty

@kouty Vous pouvez incrémenter un registre non affecté à une variable.
Polluks

20

La raison ++i peut être légèrement plus rapide que i++celle qui i++peut nécessiter une copie locale de la valeur de i avant qu'elle ne soit incrémentée, alors qu'elle ++ine le fait jamais. Dans certains cas, certains compilateurs l'optimiseront si possible ... mais ce n'est pas toujours possible, et tous les compilateurs ne le font pas.

J'essaie de ne pas trop compter sur les optimisations des compilateurs, donc je suivrais les conseils de Ryan Fox: quand je peux utiliser les deux, j'utilise ++i.


11
-1 pour la réponse C ++ à la question C. Il n'y a pas plus de "copie locale" de la valeur de iqu'il n'y en a de la valeur 1 lorsque vous écrivez une instruction 1;.
R .. GitHub STOP STOPINGING ICE

14

Le résultat effectif de l'utilisation de l'une ou l'autre dans une boucle est identique. En d'autres termes, la boucle fera exactement la même chose dans les deux cas.

En termes d'efficacité, il pourrait y avoir une pénalité à choisir i ++ plutôt que ++ i. En termes de spécification de langue, l'utilisation de l'opérateur post-incrémentation devrait créer une copie supplémentaire de la valeur sur laquelle l'opérateur agit. Cela pourrait être une source d'opérations supplémentaires.

Cependant, vous devez considérer deux problèmes principaux avec la logique précédente.

  1. Les compilateurs modernes sont excellents. Tous les bons compilateurs sont suffisamment intelligents pour se rendre compte qu'il voit un incrément entier dans une boucle for, et il optimisera les deux méthodes avec le même code efficace. Si l'utilisation de la post-incrémentation sur la pré-incrémentation entraîne en fait un ralentissement de l'exécution de votre programme, alors vous utilisez un compilateur terrible .

  2. En termes de complexité temporelle opérationnelle, les deux méthodes (même si une copie est en cours de réalisation) sont équivalentes. Le nombre d'instructions exécutées à l'intérieur de la boucle devrait dominer le nombre d'opérations dans l'opération d'incrémentation de manière significative. Par conséquent, dans toute boucle de taille significative, la pénalité de la méthode d'incrémentation sera massivement éclipsée par l'exécution du corps de boucle. En d'autres termes, vous feriez mieux de vous soucier de l'optimisation du code dans la boucle plutôt que de l'incrémentation.

À mon avis, toute la question se résume simplement à une préférence de style. Si vous pensez que la pré-incrémentation est plus lisible, utilisez-la. Personnellement, je préfère le post-incrément, mais c'est probablement parce que c'est ce qu'on m'a appris avant de savoir quoi que ce soit sur l'optimisation.

Il s'agit d'un exemple par excellence d'optimisation prématurée, et des problèmes comme celui-ci ont le potentiel de nous distraire de graves problèmes de conception. Il reste cependant une bonne question à poser, car il n'y a pas d'uniformité dans l'utilisation ou de consensus dans les "meilleures pratiques".


13

Ils incrémentent tous les deux le nombre. ++iest équivalent à i = i + 1.

i++et ++isont très similaires mais pas exactement les mêmes. Les deux incrémentent le nombre, mais ++iincrémentent le nombre avant que l'expression actuelle ne soit évaluée, tandis quei++ incrémente le nombre après que l'expression est évaluée.

Exemple:

int i = 1;
int x = i++; //x is 1, i is 2
int y = ++i; //y is 3, i is 3

8

++i(Opération Prefix): Incrément et affecte alors la valeur
(par exemple): int i = 5, int b = ++i Dans ce cas, 6 est associé à b d' abord, puis par incréments à 7 , et ainsi de suite.

i++(Opération Postfix): cessionnaires et incrémente alors la valeur
(par exemple): int i = 5,int b = i++ Dans ce cas, 5 est associé à b d' abord, puis par incréments de 6 et ainsi de suite.

Dans le cas d'une boucle for: i++ est principalement utilisé car, normalement, nous utilisons la valeur de départ de iavant d'incrémenter la boucle for. Mais selon la logique de votre programme, cela peut varier.


7

++i: est pré-incrémenté, l'autre est post-incrémenté.

i++: récupère l'élément puis l'incrémente.
++i: incrémente i puis renvoie l'élément.

Exemple:

int i = 0;
printf("i: %d\n", i);
printf("i++: %d\n", i++);
printf("++i: %d\n", ++i);

Production:

i: 0
i++: 0
++i: 2

5

Je suppose que vous comprenez maintenant la différence de sémantique (mais honnêtement, je me demande pourquoi les gens posent des questions `` qu'est-ce que l'opérateur X signifie '' sur le débordement de pile plutôt que de lire, vous savez, un livre ou un didacticiel Web ou quelque chose du genre.

Mais quoi qu'il en soit, quant à celui à utiliser, ignorez les questions de performances, qui sont peu importantes, même en C ++. Voici le principe à utiliser pour décider lequel utiliser:

Dites ce que vous voulez dire dans le code.

Si vous n'avez pas besoin de la valeur avant incrément dans votre instruction, n'utilisez pas cette forme d'opérateur. C'est un problème mineur, mais à moins que vous ne travailliez avec un guide de style qui interdit complètement une version en faveur de l'autre (alias un guide de style à tête d'os), vous devez utiliser le formulaire qui exprime le plus exactement ce que vous essayez de faire.

QED, utilisez la version pré-incrémentée:

for (int i = 0; i != X; ++i) ...

5

La différence peut être comprise par ce simple code C ++ ci-dessous:

int i, j, k, l;
i = 1; //initialize int i with 1
j = i+1; //add 1 with i and set that as the value of j. i is still 1
k = i++; //k gets the current value of i, after that i is incremented. So here i is 2, but k is 1
l = ++i; // i is incremented first and then returned. So the value of i is 3 and so does l.
cout << i << ' ' << j << ' ' << k << ' '<< l << endl;
return 0;

5

La principale différence est

  • Post i ++ ( après incrémentation ) et
  • ++ i Pre ( avant incrément )

    • poster si i =1 la boucle incrémente comme1,2,3,4,n
    • pré si i =1 la boucle incrémente comme2,3,4,5,n

5

i ++ et ++ i

Ce petit code peut aider à visualiser la différence sous un angle différent de celui des réponses déjà publiées:

int i = 10, j = 10;

printf ("i is %i \n", i);
printf ("i++ is %i \n", i++);
printf ("i is %i \n\n", i);

printf ("j is %i \n", j);
printf ("++j is %i \n", ++j);
printf ("j is %i \n", j);

Le résultat est:

//Remember that the values are i = 10, and j = 10

i is 10 
i++ is 10     //Assigns (print out), then increments
i is 11 

j is 10 
++j is 11    //Increments, then assigns (print out)
j is 11 

Faites attention aux situations avant et après.

pour boucle

Quant à savoir lequel d'entre eux doit être utilisé dans un bloc d'incrémentation d'une boucle for, je pense que le mieux que nous puissions faire pour prendre une décision est d'utiliser un bon exemple:

int i, j;

for (i = 0; i <= 3; i++)
    printf (" > iteration #%i", i);

printf ("\n");

for (j = 0; j <= 3; ++j)
    printf (" > iteration #%i", j);

Le résultat est:

> iteration #0 > iteration #1 > iteration #2 > iteration #3
> iteration #0 > iteration #1 > iteration #2 > iteration #3 

Je ne sais pas pour vous, mais je ne vois aucune différence dans son utilisation, au moins dans une boucle for.


5

Le fragment de code C suivant illustre la différence entre les opérateurs d'incrémentation et de décrémentation pré et post:

int  i;
int  j;

Opérateurs d'incrémentation:

i = 1;
j = ++i;    // i is now 2, j is also 2
j = i++;    // i is now 3, j is 2

4

Pré-crément signifie incrément sur la même ligne. Post-incrément signifie incrément après l'exécution de la ligne.

int j=0;
System.out.println(j); //0
System.out.println(j++); //0. post-increment. It means after this line executes j increments.

int k=0;
System.out.println(k); //0
System.out.println(++k); //1. pre increment. It means it increments first and then the line executes

Lorsqu'il est livré avec les opérateurs OR, AND, cela devient plus intéressant.

int m=0;
if((m == 0 || m++ == 0) && (m++ == 1)) { //false
/* in OR condition if first line is already true then compiler doesn't check the rest. It is technique of compiler optimization */
System.out.println("post-increment "+m);
}

int n=0;
if((n == 0 || n++ == 0) && (++n == 1)) { //true
System.out.println("pre-increment "+n); //1
}

Dans le tableau

System.out.println("In Array");
int[] a = { 55, 11, 15, 20, 25 } ;
int ii, jj, kk = 1, mm;
ii = ++a[1]; // ii = 12. a[1] = a[1] + 1
System.out.println(a[1]); //12

jj = a[1]++; //12
System.out.println(a[1]); //a[1] = 13

mm = a[1];//13
System.out.printf ( "\n%d %d %d\n", ii, jj, mm ) ; //12, 12, 13

for (int val: a) {
     System.out.print(" " +val); //55, 13, 15, 20, 25
}

En C ++ post / pré-incrément de variable pointeur

#include <iostream>
using namespace std;

int main() {

    int x=10;
    int* p = &x;

    std::cout<<"address = "<<p<<"\n"; //prints address of x
    std::cout<<"address = "<<p<<"\n"; //prints (address of x) + sizeof(int)
    std::cout<<"address = "<<&x<<"\n"; //prints address of x

    std::cout<<"address = "<<++&x<<"\n"; //error. reference can't re-assign because it is fixed (immutable)
}

4

Prochainement:

++iet i++fonctionne de la même manière si vous ne les écrivez pas dans une fonction. Si vous utilisez quelque chose comme function(i++)ou function(++i)vous pouvez voir la différence.

function(++i)dit le premier incrément i de 1, après cela, mettez-le idans la fonction avec une nouvelle valeur.

function(i++)dit mettre d'abord idans la fonction après cet incrément ide 1.

int i=4;
printf("%d\n",pow(++i,2));//it prints 25 and i is 5 now
i=4;
printf("%d",pow(i++,2));//it prints 16 i is 5 now

2
La différence n'est pas vraiment liée aux appels de fonction (et vous pouvez repérer la différence sans faire d'appels de fonction). Il y a une différence entre int j = ++i;et int k = i++;même quand aucun appel de fonction n'est impliqué.
Jonathan Leffler

3

La seule différence est l'ordre des opérations entre l'incrément de la variable et la valeur retournée par l'opérateur.

Ce code et sa sortie expliquent la différence:

#include<stdio.h>

int main(int argc, char* argv[])
{
  unsigned int i=0, a;
  a = i++;
  printf("i before: %d; value returned by i++: %d, i after: %d\n", i, a, i);
  i=0;
  a = ++i;
  printf("i before: %d; value returned by ++i: %d, i after: %d\n", i, a, i);
}

La sortie est:

i before: 1; value returned by i++: 0, i after: 1
i before: 1; value returned by ++i: 1, i after: 1

Donc, ++iretourne essentiellement la valeur après son incrémentation, tout en ++iretournant la valeur avant son incrémentation. À la fin, dans les deux cas, la ivaleur sera incrémentée.

Un autre exemple:

#include<stdio.h>

int main ()
  int i=0;
  int a = i++*2;
  printf("i=0, i++*2=%d\n", a);
  i=0;
  a = ++i * 2;
  printf("i=0, ++i*2=%d\n", a);
  i=0;
  a = (++i) * 2;
  printf("i=0, (++i)*2=%d\n", a);
  i=0;
  a = (++i) * 2;
  printf("i=0, (++i)*2=%d\n", a);
  return 0;
}

Production:

i=0, i++*2=0
i=0, ++i*2=2
i=0, (++i)*2=2
i=0, (++i)*2=2

Plusieurs fois, il n'y a pas de différence

Les différences sont claires lorsque la valeur retournée est affectée à une autre variable ou lorsque l'incrément est effectué en concaténation avec d' autres opérations où la priorité des opérations est appliquée ( i++*2est différent ++i*2, mais (i++)*2et (++i)*2retourne la même valeur) dans de nombreux cas , ils sont interchangeables. Un exemple classique est la syntaxe de boucle for:

for(int i=0; i<10; i++)

a le même effet de

for(int i=0; i<10; ++i)

Règle à retenir

Pour ne faire aucune confusion entre les deux opérateurs j'ai adopté cette règle:

Associer la position de l'opérateur ++par rapport à la variable ià l'ordre de l' ++opération par rapport à l'affectation

Autrement dit:

  • ++ avant i signifie que l'incrémentation doit être effectuée avant l' affectation;
  • ++ après l' i incrémentation doit être effectuée après l' affectation:

3

Vous pouvez considérer la conversion interne de cela comme plusieurs déclarations ;

  • cas 1
i++;

vous pouvez le penser comme,

i;
i = i+1;
  • cas 2
++i;

vous pouvez le penser comme,

i = i+i;
i;

-3

a = i ++ signifie a contient la valeur i actuelle a = ++ i signifie a contient la valeur i incrémentée


10
Cette réponse n'est pas exacte. a = i++;signifie que la valeur stockée dans asera la valeur d' iavant l'incrémentation, mais "sans incrémentation" implique qu'elle in'est pas incrémentée, ce qui est complètement faux -i est incrémenté, mais la valeur de l'expression est la valeur avant l'incrémentation.
Jonathan Leffler

-6

Voici l'exemple pour comprendre la différence

int i=10;
printf("%d %d",i++,++i);

sortie: 10 12/11 11(selon l'ordre d'évaluation des arguments de la printffonction, qui varie selon les compilateurs et les architectures)

Explication: i++->i est imprimé, puis incrémente. (Imprime 10, mais ideviendra 11) ++i-> la ivaleur augmente et imprime la valeur. (Imprime 12, et la valeur de iégalement 12)


11
Cela provoque un comportement indéfini car il n'y a pas de point de séquence entre i++et++i
MM

@Lundin est-ce correct cependant, les LHS, RHS de virgules ont un point de séquence entre eux mais les 2 expressions sont toujours non séquencées l'une par rapport à l'autre
Antti Haapala
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.