Comment puis-je mettre deux instructions d’incrémentation dans une boucle C ++ ‘for’?

Je voudrais incrémenter deux variables dans une condition for -loop au lieu d’une.

Donc quelque chose comme:

 for (int i = 0; i != 5; ++i and ++j) do_something(i, j); 

Quelle est la syntaxe pour cela?

Un idiome commun consiste à utiliser l’ opérateur de virgule qui évalue les deux opérandes et renvoie le second opérande. Ainsi:

 for(int i = 0; i != 5; ++i,++j) do_something(i,j); 

Mais est-ce vraiment un opérateur virgule?

Maintenant, après avoir écrit cela, un commentateur a suggéré qu’il s’agissait en fait d’un sucre syntaxique spécial dans le for et non d’un opérateur de virgule. J’ai vérifié cela dans GCC comme suit:

 int i=0; int a=5; int x=0; for(i; i<5; x=i++,a++){ printf("i=%da=%dx=%d\n",i,a,x); } 

Je m'attendais à ce que x prenne la valeur originale de a, il aurait donc dû afficher 5,6,7 .. pour x. Ce que j'ai eu c'était ça

 i=0 a=5 x=0 i=1 a=6 x=0 i=2 a=7 x=1 i=3 a=8 x=2 i=4 a=9 x=3 

Cependant, si je mettais l'expression entre crochets pour forcer l'parsingur à voir un opérateur de virgule, je

 int main(){ int i=0; int a=5; int x=0; for(i=0; i<5; x=(i++,a++)){ printf("i=%da=%dx=%d\n",i,a,x); } } i=0 a=5 x=0 i=1 a=6 x=5 i=2 a=7 x=6 i=3 a=8 x=7 i=4 a=9 x=8 

Au départ, je pensais que cela montrait qu’il ne se comportait pas du tout comme une virgule, mais il s’agit simplement d’un problème de priorité - l’opérateur de virgule a la priorité la plus basse possible , donc l’expression x = i ++, a ++ est efficace analysé comme (x = i ++), a ++

Merci pour tous les commentaires, c'était une expérience d'apprentissage intéressante, et j'utilise C depuis de nombreuses années!

Essaye ça

 for(int i = 0; i != 5; ++i, ++j) do_something(i,j); 

Essayez de ne pas le faire!

De http://www.research.att.com/~bs/JSF-AV-rules.pdf :

Règle AV 199
L’expression d’incrémentation dans une boucle for n’effectuera aucune autre action que de changer un paramètre de boucle unique à la valeur suivante pour la boucle.

Justification: lisibilité.

 for (int i = 0; i != 5; ++i, ++j) do_something(i, j); 

Je suis venu ici pour me rappeler comment coder un deuxième index dans la clause d’incrémentation d’une boucle FOR, ce que je savais peut être fait principalement en l’observant dans un échantillon que j’ai incorporé dans un autre projet, écrit en C ++.

Aujourd’hui, je travaille en C #, mais je suis sûr qu’il obéirait aux mêmes règles à cet égard, car la déclaration FOR est l’une des plus anciennes structures de contrôle de toute la programmation. Heureusement, j’ai récemment passé plusieurs jours à documenter avec précision le comportement d’une boucle FOR dans l’un de mes anciens programmes C, et j’ai rapidement compris que ces études contenaient des leçons applicables au problème C # actuel, en particulier au comportement de la deuxième variable d’index. .

Pour les imprudents, voici un résumé de mes observations. Tout ce que j’ai vu se produire aujourd’hui, en observant attentivement les variables dans la fenêtre Locals, a confirmé que je m’attendais à ce qu’une instruction C # FOR se comporte exactement comme une instruction FOR C ou C ++.

  1. La première fois qu’une boucle FOR est exécutée, la clause d’incrémentation (la troisième de ses trois) est ignorée. Dans Visual C et C ++, l’incrément est généré sous forme de trois instructions machine au milieu du bloc qui implémente la boucle, de sorte que la première passe exécute le code d’initialisation une seule fois, puis saute le bloc d’incrémentation pour exécuter le test de terminaison. Cela implémente la fonctionnalité selon laquelle une boucle FOR s’exécute zéro fois ou plus, en fonction de l’état de ses variables d’index et de limites.
  2. Si le corps de la boucle s’exécute, sa dernière instruction est un saut vers la première des trois instructions d’incrément ignorées par la première itération. Après leur exécution, le contrôle tombe naturellement dans le code de test de limite qui implémente la clause middle. Le résultat de ce test détermine si le corps de la boucle FOR s’exécute ou si le contrôle transfère à l’instruction suivante au-delà du saut au bas de son étendue.
  3. Puisque le contrôle transfère du bas du bloc de boucle FOR au bloc d’incrémentation, la variable d’index est incrémentée avant l’exécution du test. Non seulement ce comportement explique pourquoi vous devez coder vos clauses limites de la manière que vous avez apprise, mais il affecte également tout incrément secondaire que vous ajoutez, via l’opérateur de virgule, car il devient partie intégrante de la troisième clause. Par conséquent, il n’est pas modifié à la première itération, mais à la dernière itération, qui n’exécute jamais le corps.

Si l’une de vos variables d’index rest dans la scope à la fin de la boucle, leur valeur sera supérieure au seuil qui arrête la boucle, dans le cas de la variable d’index vraie. De même, si, par exemple, la deuxième variable est initialisée à zéro avant l’entrée de la boucle, sa valeur à la fin sera le nombre d’itérations, en supposant qu’il s’agit d’un incrément (++), et non d’un décrément, et que rien dans le corps de la boucle change de valeur.

Je suis d’accord avec squelart. L’incrémentation de deux variables est sujette à des bogues, surtout si vous ne testez qu’un seul d’entre eux.

C’est la manière lisible de faire ceci:

 for(int i = 0; i < 5; ++i) { ++j; do_something(i, j); } 

For boucles For sont destinées aux cas où votre boucle s'exécute sur une variable croissante / décroissante. Pour toute autre variable, changez-la dans la boucle.

Si vous avez besoin de j pour être lié à i , pourquoi ne pas laisser la variable originale telle quelle et append i ?

 for(int i = 0; i < 5; ++i) { do_something(i,a+i); } 

Si votre logique est plus complexe (par exemple, vous devez contrôler plus d'une variable), j'utiliserais une boucle while.

 int main(){ int i=0; int a=0; for(i;i<5;i++,a++){ printf("%d %d\n",a,i); } } 

Utilisez les mathématiques. Si les deux opérations dépendent mathématiquement de l’itération de la boucle, pourquoi ne pas faire le calcul?

 int i, j;//That have some meaningful values in them? for( int counter = 0; counter < count_max; ++counter ) do_something (counter+i, counter+j); 

Ou, plus spécifiquement en référence à l'exemple de l'OP:

 for(int i = 0; i != 5; ++i) do_something(i, j+i); 

Surtout si vous passez à une fonction par valeur, alors vous devriez obtenir quelque chose qui fait exactement ce que vous voulez.