Question

Je voudrais incrémenter deux variables dans une condition pour -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?

Était-ce utile?

La solution

Un idiome courant consiste à utiliser le 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 de virgule?

Après avoir écrit cela, un commentateur a suggéré qu'il s'agissait en fait d'un sucre syntaxique spécial dans l'instruction 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=%d a=%d x=%d\n",i,a,x);
}

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

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 met l'expression entre crochets pour forcer l'analyseur à vraiment voir un opérateur de virgule, je reçois ceci

int main(){
    int i=0;
    int a=5;
    int x=0;

    for(i=0; i<5; x=(i++,a++)){
        printf("i=%d a=%d x=%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

Initialement, je pensais que cela montrait qu’il ne se comportait pas du tout comme un opérateur de virgule, mais il s’avère qu’il s’agit simplement d’un problème de priorité. L’opérateur de virgule a le priorité la plus basse possible , de sorte que l'expression x = i ++, un ++ est effectivement analysée sous la forme (x = i ++), un ++

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

Autres conseils

Essayez ceci

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 incrémentée dans une boucle for n’exécutera aucune action autre que celle de modifier une seule   paramètre de boucle à 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 qui, je le savais, pourrait être fait principalement en l'observant dans un exemple que j'ai incorporé à un autre projet, écrit en C ++.

Aujourd'hui, je travaille en C #, mais je suis convaincu qu'il obéira aux mêmes règles à cet égard, car la déclaration FOR est l'une des structures de contrôle les plus anciennes de toute la programmation. Heureusement, j'avais récemment passé plusieurs jours à documenter avec précision le comportement d'une boucle FOR dans l'un de mes anciens programmes C et je me suis vite rendu compte que ces études contenaient des leçons qui s'appliquent 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 de la fenêtre Locals, a confirmé mon attente selon laquelle une instruction FOR pour C # se comporte exactement comme une instruction FOR pour 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 la forme de trois instructions machine au milieu du bloc qui implémente la boucle, de sorte que la passe initiale n'exécute le code d'initialisation qu'une seule fois, puis saute par-dessus le bloc d'incrément pour exécuter le test de terminaison. Cela implémente la fonctionnalité qu'une boucle FOR ne s'exécute pas plus d'une fois, en fonction de l'état de son index et de ses variables 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émentation ignorées par la première itération. Après leur exécution, le contrôle tombe naturellement dans le code de test limite qui implémente la clause middle. Le résultat de ce test détermine si le corps de la boucle FOR est exécuté ou si le contrôle est transféré à l'instruction suivante après le saut situé au bas de son étendue.
  3. Etant donné que les contrôles passent du bas du bloc de boucle FOR au bloc d’incrément, 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 limit comme vous l'avez appris, mais il affecte également tout incrément secondaire que vous ajoutez via l'opérateur virgule, car il fait partie 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 reste dans la portée à la fin de la boucle, sa valeur sera supérieure au seuil qui arrête la boucle, dans le cas de la vraie variable d'index. De même, si, par exemple, la deuxième variable est initialisée à zéro avant la boucle, sa valeur à la fin sera le compte d'itérations, en supposant qu'il s'agit d'un incrément (++), pas d'un décrément, et que rien le corps de la boucle change de valeur.

Je suis d'accord avec squelart. Incrémenter deux variables est sujet à des bogues, surtout si vous ne testez que l’une d’elles.

C’est le moyen lisible de le faire:

for(int i = 0; i < 5; ++i) {
    ++j;
    do_something(i, j);
}
Les 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 souhaitez que j soit lié à i , pourquoi ne pas laisser la variable d'origine en l'état et ajouter i ?

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

Si votre logique est plus complexe (par exemple, vous devez surveiller 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, en vous référant plus particulièrement à l'exemple du PO:

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

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top