web-dev-qa-db-fra.com

Du jamais vu en C ++ pour la boucle

Je convertissais un algorithme C++ en C #. Je suis tombé sur cette boucle:

for (u = b.size(), v = b.back(); u--; v = p[v]) 
b[u] = v;

Il ne donne aucune erreur en C++, mais il le fait en C # (ne peut pas convertir int en bool). Je ne peux vraiment pas comprendre cela pour la boucle, où est la condition?

Quelqu'un peut-il expliquer?

PS. Juste pour vérifier, pour adapter un VECTEUR à une LISTE, b.back () correspond-il à b [b.Count-1]?

163
Thomas

La condition de la boucle for est au milieu - entre les deux points-virgules ;.

En C++, il est OK de mettre presque n'importe quelle expression comme condition: tout ce qui évalue à zéro signifie false; non nul signifie true.

Dans votre cas, la condition est u--: lorsque vous convertissez en C #, ajoutez simplement != 0:

for (u = b.size(), v = b.back(); u-- != 0; v = p[v]) 
    b[u] = v; //                     ^^^^ HERE
319
dasblinkenlight

Beaucoup de réponses précises, mais je pense que cela vaut la peine d'écrire la boucle while équivalente.

for (u = b.size(), v = b.back(); u--; v = p[v]) 
   b[u] = v;

Est équivalent à:

u = b.size();
v = b.back();
while(u--) {
   b[u] = v;
   v = p[v];
}

Vous pourriez envisager de refactoriser le format while () lorsque vous traduisez en C #. À mon avis, c'est plus clair, moins un piège pour les nouveaux programmeurs, et tout aussi efficace.

Comme d'autres l'ont souligné - mais pour compléter ma réponse - pour que cela fonctionne en C #, vous devez remplacer while(u--) par while(u-- != 0).

... ou while(u-- >0) juste au cas où u commence négatif. (OK, b.size() ne sera jamais négatif - mais considérons un cas général où peut-être quelque chose d'autre a initialisé u).

Ou, pour le rendre encore plus clair:

u = b.size();
v = b.back();
while(u>0) {
   u--;
   b[u] = v;
   v = p[v];
}

Il vaut mieux être clair que d'être concis.

165
slim

La condition est u--;, car il se trouve en deuxième position de l'instruction pour .

Si la valeur de u--; est différent de 0, il sera interprété comme true (c'est-à-dire implicitement casté à la valeur booléenne true). Si, au contraire, sa valeur est 0, il sera converti en false.

C'est très mauvais code .

Mise à jour: J'ai discuté de l'écriture des boucles "for" dans ce article de blog . Ses recommandations peuvent être résumées dans les paragraphes suivants:

Une boucle for est une construction pratique, lisible (une fois que vous vous y êtes habitué) et laconique, mais vous devez bien l'utiliser. En raison de sa syntaxe inhabituelle, son utilisation d'une manière trop imaginative n'est pas une bonne idée.

Toutes les parties de la boucle for doivent être courtes et lisibles. Les noms de variables doivent être choisis pour être faciles à comprendre.

Cet exemple viole clairement ces recommandations.

65
Daniel Daranas

Ce sera la forme C # de votre boucle.

// back fetches the last element of vector in c++.
for (u = b.size(), v = b.back(); (u--) != 0; v = p[v]) 
{      
  b[u] = v;      
}

Remplacez simplement l'équivalent pour size () et back ().

Ce qu'il fait est inverse la liste et stocke dans un tableau. Mais en C #, nous avons directement une fonction définie par le système pour cela. Vous n'avez donc pas besoin d'écrire cette boucle également.

b = b.Reverse().ToArray();
23
Narendra

La condition est le résultat de u--, Qui est la valeur de u avant sa décrémentation.

En C et C++, un intis convertible en bool en faisant implicitement une comparaison != 0 (0 est false, tout le reste est true).

b.back() est le dernier élément d'un conteneur, qui est b[b.size() - 1], lorsque size() != 0.

14
Bo Persson
u = b.size(), v = b.back()

est l'initialisation.

u--

est la condition.

v = p[v]

est l'itération

14

En C, tout ce qui n'est pas nul est true dans des contextes "booléens", comme la condition de fin de boucle ou une instruction conditionnelle. En C #, vous devez rendre ce contrôle explicite: u-- != 0.

11
Joey

Comme indiqué par d'autres, le fait que C++ ait une conversion implicite en booléen signifie que le conditionnel est u--, Ce qui sera vrai si la valeur n'est pas nulle.

Il convient d'ajouter que vous avez une fausse hypothèse en demandant "où est le conditionnel". Dans C++ et C # (et dans d'autres langages de syntaxe similaire), vous pouvez avoir un conditionnel vide. Dans ce cas, il a toujours la valeur true, donc la boucle continue indéfiniment ou jusqu'à ce qu'une autre condition la quitte (via return, break ou throw).

for(int i = 0; ; ++i)
  doThisForever(i);

En effet, n'importe quelle partie de l'instruction for peut être omise, auquel cas elle n'est tout simplement pas exécutée.

En général, for(A; B; C){D} ou for(A; B; C)D; devient:

{A}
loopBack:
if(!(B))
  goto escapeLoop;
{D}
{C}
goto loopBack;
escapeLoop:

Un ou plusieurs de A, B, C ou D peuvent être omis.

En conséquence, certains favorisent for(;;) pour les boucles infinies. Je le fais parce que tandis que while(true) est plus populaire, je le lis comme "jusqu'à ce que la vérité finisse par être vraie", ce qui semble quelque peu apocalyptique par rapport à ma lecture for(;;) comme "pour toujours".

C'est une question de goût, mais comme je ne suis pas la seule personne au monde à aimer for(;;) cela vaut la peine de savoir ce que cela signifie.

6
Jon Hanna

toutes les réponses sont correctes: -

la boucle for peut être utilisée de différentes manières, comme suit:

Single Statement inside For Loop
Multiple Statements inside For Loop
No Statement inside For Loop
Semicolon at the end of For Loop
Multiple Initialization Statement inside For
Missing Initialization in For Loop
Missing Increment/Decrement Statement
Infinite For Loop
Condition with no Conditional Operator.
4
birubisht
for (u = b.size(), v = b.back(); u--; v = p[v]) 
   b[u] = v;

Dans le code ci-dessus, u et v sont initialisés avec b.size() et b.back().

Chaque fois que la condition est vérifiée, elle exécute également l'instruction de décrémentation, c'est-à-dire u--.

La boucle for se fermera lorsque u deviendra 0.

4
Apte

Si vous êtes habitué à C/C++, ce code n'est pas si difficile à lire, bien qu'il soit assez concis et pas si génial. Alors laissez-moi vous expliquer les parties qui sont plus Cism qu'autre chose. Tout d'abord, la syntaxe générale d'une boucle C for ressemble à ceci:

for (<initialization> ; <condition>; <increment>)
{
    <code...>
}

Le code d'initialisation est exécuté une fois. Ensuite, la condition est testée avant chaque boucle et enfin l'incrément est appelé après chaque boucle. Ainsi, dans votre exemple, vous constaterez que la condition est u--

Pourquoi u-- fonctionne comme condition en C et non en C #? Parce que C convertit implicitement beaucoup de choses trop booléennes et cela peut causer des problèmes. Pour un nombre, tout ce qui est différent de zéro est vrai et zéro est faux. Donc, il décomptera de b.size () - 1 à 0. Avoir l'effet secondaire dans la condition est un peu ennuyeux et il serait préférable de le mettre dans la partie incrémentielle de la boucle for, bien que beaucoup de C le code fait cela. Si je l'écrivais, je le ferais plus comme ceci:

for (u = b.size() - 1, v = b.back(); u>=0; --u) 
{
    b[u] = v;
    v = p[v]
}

La raison en est, pour moi au moins, c'est plus clair. Chaque partie de la boucle for fait son travail et rien d'autre. Dans le code d'origine, la condition modifiait la variable. La partie incrémentale faisait quelque chose qui devrait être dans le bloc de code, etc.

L'opérateur virgule peut également vous lancer pour une boucle. En C quelque chose comme x=1,y=2 ressemble à une instruction en ce qui concerne le compilateur et s'inscrit dans le code d'initialisation. Il évalue simplement chacune des parties et renvoie la valeur de la dernière. Ainsi, par exemple:

std::cout << "(1,2)=" << (1,2) << std::endl;

imprimerait 2.

3
Matt Price

L'erreur rencontrée dans C # lui-même efface le doute. La boucle for recherche un

FALSE

condition de résiliation. Et comme nous le savons,

(BOOL) FALSE = (int) 0

mais C # ne peut pas le traiter seul contrairement à C++. La condition que vous recherchez est donc

u--

mais vous devez donner explicitement la condition en C # comme

u--! = 0

ou

u--> 0

Mais essayez toujours d'éviter ce genre de pratique de codage. le

en boucle

indiqué ci-dessus en réponse est l'une des versions les plus simplifiées de votre

for-loop.

3
Abhineet