Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1612 connectés 

  FORUM HardWare.fr
  Programmation
  C

  [c] Question sur une boucle do...while

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[c] Question sur une boucle do...while

n°1597038
rcrc61
Posté le 08-08-2007 à 09:55:44  profilanswer
 

Bonjour à tous, voilà j'ai un petit problème en C, en fait je ne comprends pas pourquoi je ne peux pas utiliser le "OU" logique : || dans ce programme et que je doive utiliser le "OU" binaire : |.
 
Voici la boucle en question :
 

Code :
  1. do
  2.   {
  3.   printf("Veuillez entrer la base du nombre initial : (10 = decimale, min 2 - max 16)\n" ) ;
  4.   scanf("%d", &base_1) ;
  5.   printf("%d", base_1) ;
  6.   }
  7.   while ( base_1<2 | base_1>16 ) ;

mood
Publicité
Posté le 08-08-2007 à 09:55:44  profilanswer
 

n°1597041
rcrc61
Posté le 08-08-2007 à 10:00:17  profilanswer
 

Desolé j'ai fait une erreur, le || fonctionne bien aussi mais ce que je voulais savoir c'etait pourquoi le | fonctionne lui.

n°1597096
mrbebert
Posté le 08-08-2007 à 11:33:52  profilanswer
 

Je pense que la comparaison renvoie "1" lorsqu'elle est vrai, 0 si fausse. Donc, comme on ne s'intéresse qu'au 1er bit, le |  a le même résultat que le || [:figti]

n°1597433
Sve@r
Posté le 08-08-2007 à 19:34:28  profilanswer
 

mrbebert a écrit :

Je pense que la comparaison renvoie "1" lorsqu'elle est vrai, 0 si fausse. Donc, comme on ne s'intéresse qu'au 1er bit, le |  a le même résultat que le || [:figti]


 
Exactement. Si tu écris "cond1 || cond2" il s'agit d'un ou logique qui obéit aux règles booléennes qui sera vrai si l'une des deux conditions est vérifiée. Le résultat numérique de cette écriture devrait être (suis pas sûr dans ce coup là) la valeur de la première condition vraie
ex: int a; a=(5 || 8)   => je pense que "a" vaudra 5 mais dans tout les cas, le test "if (5 || 8)" est vrai.
 
Dans la 2° écriture, si tu écris "cond1 | cond2", il s'agit d'une opération mathématique sur chaque bit de "cond1" pris avec chaque bit de "cond2". Si un seul des bits vaut 1, l'ensemble complet ne vaudra pas 0 donc sera considéré comme vrai. Mais il s'agit d'un jonglage mathématique associé à la caractéristique du C concernant l'évaluation de ses booléens (0 = faux, pas 0 = vrai) et non d'une vraie expression booléenne.
 
PS: Je ne vois pas trop le rapport de ce topic avec une boucle do...while... mais ça me rappelle une fois j'avais posé à mes élèves 3 boucles pièges (en leur disant bien que c'était piégé) et je leur demandait d'évaluer le comportement des boucles
 
La première assez simple

int i;
for (i=1; i != 10; i++)
    printf("i=%d\n", i++);


 
La seconde plus subtile

unsigned char i;
for (i=1; i < 300; i++)
    printf("i=%d\n", i);


 
La troisième vraiment ignoble

int i;
i=100;
do {
    printf("i=%d\n", i);
    i--;
} while (i > 5 > 4);


Ca avait été un bon moment de bonne humeur  :D


Message édité par Sve@r le 08-08-2007 à 19:41:13

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1597547
Un Program​meur
Posté le 09-08-2007 à 09:19:36  profilanswer
 

Dans le genre piege:
 

Code :
  1. size_t i;
  2. for (i = sizeof table/sizeof *table - 1; i > 0; --i) {
  3.   ...
  4. }

n°1597556
matafan
Posté le 09-08-2007 à 09:50:47  profilanswer
 

Je dois pas être bien réveillé, mais je vois pas le piège ?

n°1597565
Sve@r
Posté le 09-08-2007 à 10:16:45  profilanswer
 

matafan a écrit :

Je dois pas être bien réveillé, mais je vois pas le piège ?


Ben tu traites pas l'élément [0] !!! (mais oui, moi aussi ça m'a pas sauté aux yeux immédiatements  ;) )

Message cité 1 fois
Message édité par Sve@r le 09-08-2007 à 10:17:39

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1597567
Un Program​meur
Posté le 09-08-2007 à 10:22:29  profilanswer
 

Sve@r a écrit :


Ben tu traites pas l'élément [0] !!! (mais oui, moi aussi ça m'a pas sauté aux yeux immédiatements  ;) )


 
C'est le premier.  Le deuxieme piege, c'est que
 

Code :
  1. size_t i;
  2. for (i = sizeof table/sizeof *table - 1; i >= 0; --i) {
  3.        ...
  4. }


n'est toujours pas bon.

n°1597579
Sve@r
Posté le 09-08-2007 à 10:48:30  profilanswer
 

Un Programmeur a écrit :


 
C'est le premier.  Le deuxieme piege, c'est que
 

Code :
  1. size_t i;
  2. for (i = sizeof table/sizeof *table - 1; i >= 0; --i) {
  3.        ...
  4. }


n'est toujours pas bon.


 
Oui mais celui-là, comme je me suis déjà fait avoir avec, je le connais ;)
Ca marchera si tu mets "ssize_t i" mais perso, si je dois écrire une boucle de ce style, je préfère commencer à sizeof(table)/sizeof(*table) et bosser sur "i - 1"...

Message cité 1 fois
Message édité par Sve@r le 09-08-2007 à 10:48:42

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1597596
matafan
Posté le 09-08-2007 à 11:24:19  profilanswer
 

Le coup de pas traiter l'élément 0 j'avais vu mais bon, c'est pas un piège, j'imagine que si on met > 0 en test de fin de boucle c'est qu'on ne veut pas traiter l'élément 0... A mon avis notre ami pensait au piège unsigned / >= 0, et s'est planté dans son message ;)

mood
Publicité
Posté le 09-08-2007 à 11:24:19  profilanswer
 

n°1597618
Sve@r
Posté le 09-08-2007 à 11:49:22  profilanswer
 

matafan a écrit :

A mon avis notre ami pensait au piège unsigned / >= 0, et s'est planté dans son message ;)


Non, c'est le sujet de son 2° post.  ;)   ;)  
 

matafan a écrit :

Le coup de pas traiter l'élément 0 j'avais vu mais bon, c'est pas un piège, j'imagine que si on met > 0 en test de fin de boucle c'est qu'on ne veut pas traiter l'élément 0


Non. C'est plutôt le programmeur qui programme une boucle dans le bon sens. Par exemple il a créé 10 alloc dans un tableau de pointeurs et il veut les libérer

Code :
  1. for (i=0; i < 10; i++)
  2.    free(pt[i]);


 
Puis, il se dit que ce serait plus esthétique de libérer les pointeurs dans l'ordre inverse de leur création, comme si la mémoire était un lifo et que c'est plus sensé de les libérer à l'envers (et ça peut se justifier si l'élément "i" sert de support à l'élément "i + 1" ). Donc s'il fait pas trop gaffe, il inversera simplement les opérandes sans vraiment y penser

Code :
  1. for (i=10; i > 0; i--)
  2.    free(pt[i]);


Le piège stupide quoi... (et en plus il commence hors tableau)


Message édité par Sve@r le 09-08-2007 à 14:51:15

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1597654
matafan
Posté le 09-08-2007 à 13:05:55  profilanswer
 

[:azitwaz]

n°1597682
Un Program​meur
Posté le 09-08-2007 à 14:17:03  profilanswer
 

Sve@r a écrit :

perso, si je dois écrire une boucle de ce style, je préfère commencer à sizeof(table)/sizeof(*table) et bosser sur "i - 1"...


 

Code :
  1. size_t i;
  2. for (i = sizeof table/sizeof *table; i-- > 0; /* nothing */) {
  3.    ...
  4. }

n°1597690
Un Program​meur
Posté le 09-08-2007 à 14:30:21  profilanswer
 

matafan a écrit :

Le coup de pas traiter l'élément 0 j'avais vu mais bon, c'est pas un piège, j'imagine que si on met > 0 en test de fin de boucle c'est qu'on ne veut pas traiter l'élément 0... A mon avis notre ami pensait au piège unsigned / >= 0, et s'est planté dans son message ;)


 
Le piege est qu'on n'est pas dans la situation idiomatique de traiter des intervalles comprenant la borne initiale mais pas la finale.  Dans mon exemple j'avais deja corrige en partie mais pas tout, le probleme avec le comportement des non signes etait bien un deuxieme.
 
Question auxilliaire, comme faire une boucle sur les nombres de debut a fin, y compris les deux bornes mais vide si debug > fin.

Code :
  1. void f(long debut, long fin) {
  2.    long i;
  3.    for ( /* a remplir */ ) {
  4.       ...
  5.    }


(Et la je suis interesse par une belle solution)

n°1597693
Sve@r
Posté le 09-08-2007 à 14:33:11  profilanswer
 

Un Programmeur a écrit :


 

Code :
  1. size_t i;
  2. for (i = sizeof table/sizeof *table; i-- > 0; /* nothing */) {
  3.    ...
  4. }



 
Ah oui, décrémenter i lors de son évaluation pour que le traitement se fasse sur "i -1" c'est assez fin. J'y avais point pensé. Mais dans ce genre d'écriture on frôle dangereusement le point où le code devient porc (the pig's point). Evidemment tout se discute... :D
 

Un Programmeur a écrit :

Question auxilliaire, comme faire une boucle sur les nombres de debut a fin, y compris les deux bornes mais vide si debut > fin.

Code :
  1. void f(long debut, long fin) {
  2.    long i;
  3.    for ( /* a remplir */ ) {
  4.       ...
  5.    }




Euh... ça me semble trivial (ou alors j'ai pas compris le pb) !!!

Code :
  1. void f(long debut, long fin) {
  2.    long i;
  3.    for (i=debut; i <= fin; i++) {
  4.       ...
  5.    }


Il est évident que si "debut > fin", la boucle ne se fera pas et restera vide !!!
 

Un Programmeur a écrit :

(Et la je suis interesse par une belle solution)


Noproblemo

Code :
  1. void f(long debut, long fin) {
  2.    long i;
  3.    if (debut > fin && fin < debut) goto apres;
  4.    for (i=debut; i <= fin; i++) {
  5.       ...
  6.    }
  7.     apres:
  8.        ...


Ca c'est magnifique non ??? :sol:


Message édité par Sve@r le 09-08-2007 à 14:51:48

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1597703
Un Program​meur
Posté le 09-08-2007 à 14:57:20  profilanswer
 

Et si fin = LONG_MAX ?

n°1597712
matafan
Posté le 09-08-2007 à 15:22:30  profilanswer
 

Facile, tu passes en long long ;)

n°1597806
Sve@r
Posté le 09-08-2007 à 16:33:37  profilanswer
 

Un Programmeur a écrit :

Et si fin = LONG_MAX ?


Ah oui, boucle infinie (si "i" reste long). Mais dans ce cas, debut peut pas être > fin...

Message cité 1 fois
Message édité par Sve@r le 09-08-2007 à 16:36:46

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1597835
Un Program​meur
Posté le 09-08-2007 à 16:51:21  profilanswer
 

Sve@r a écrit :


Ah oui, boucle infinie (si "i" reste long). Mais dans ce cas, debut peut pas être > fin...


Le probleme est d'ecrire un code le plus simple possible que marche dans tous les cas.

n°1597870
Sve@r
Posté le 09-08-2007 à 17:24:45  profilanswer
 

Un Programmeur a écrit :


Le probleme est d'ecrire un code le plus simple possible que marche dans tous les cas.


 
for (i=debut; i <= fin && fin + 1 > fin; i++)

Message cité 1 fois
Message édité par Sve@r le 09-08-2007 à 21:16:24

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1597903
Un Program​meur
Posté le 09-08-2007 à 17:41:51  profilanswer
 

Sve@r a écrit :


 
for (i=depart; i <= arrivee && arrivee + 1 > arrivee; i++)


 
arrivee + 1 > fin je suppose.  Ne fonctionne pas pour fin = LONG_MAX

n°1597968
Sve@r
Posté le 09-08-2007 à 20:23:50  profilanswer
 

Un Programmeur a écrit :


 
arrivee + 1 > fin je suppose.  Ne fonctionne pas pour fin = LONG_MAX


 
Non, c'est bien "fin + 1 > fin" que je voulais dire (j'ai modifié mon post). Si fin = LONG_MAX, fin + 1 = LONG_MIN et le test sera faux

Message cité 1 fois
Message édité par Sve@r le 09-08-2007 à 21:16:53

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1597977
Un Program​meur
Posté le 09-08-2007 à 21:35:07  profilanswer
 

Sve@r a écrit :


 
Non, c'est bien "fin + 1 > fin" que je voulais dire (j'ai modifié mon post). Si fin = LONG_MAX, fin + 1 = LONG_MIN et le test sera faux


 
Et on ne passe pas dans la boucle.  De plus, j'aime pas les comportements indéfinis (et dépasser LONG_MAX avec un calcul sur des entiers en est un, voir  http://gcc.gnu.org/ml/gcc/2006-12/msg00459.html pour la tendance des optimiseurs à utiliser de plus en plus les ouvertures offertes par les comportements indéfinis).

Code :
  1. if (debut <= fin) {
  2.    long i = debut;
  3.    do {
  4.       ...
  5.    } while (i != fin && (i++, 1));
  6. }


est la manière la plus simple que j'ai trouvé qui n'a aucun problème (si on accepte l'overflow sur long, i++ != fin est un peu plus simple) mais on ne peut pas dire que j'apprécie.

Code :
  1. for (i = debut, done = i > fin; !done; (i != fin && ++i) || (done = 1)) {
  2.    ...
  3. }

fonctionne aussi mais ne me plait pas plus.

Message cité 1 fois
Message édité par Un Programmeur le 09-08-2007 à 22:01:39
n°1597988
Sve@r
Posté le 09-08-2007 à 22:22:52  profilanswer
 

Un Programmeur a écrit :

Et on ne passe pas dans la boucle.


Ben c'est ce que j'ai compris en lisant la phrase

Citation :

...mais vide si debut > fin...


 
Maintenant je comprends que tu veux une boucle qui puisse traiter toute la gamme des valeurs possibles.
 

Un Programmeur a écrit :

De plus, j'aime pas les comportements indéfinis (et dépasser LONG_MAX avec un calcul sur des entiers en est un, voir  http://gcc.gnu.org/ml/gcc/2006-12/msg00459.html pour la tendance des optimiseurs à utiliser de plus en plus les ouvertures offertes par les comportements indéfinis).


Tu es plus pointu que moi. Je vais pas jouer la faignasse mais s'il me fallait lire toute la normalisation du dernier détail j'en finirais plus...

Un Programmeur a écrit :

Code :
  1. if (debut <= fin) {
  2.    long i = debut;
  3.    do {
  4.       ...
  5.    } while (i != fin && (i++, 1));
  6. }


est la manière la plus simple que j'ai trouvé qui n'a aucun problème (si on accepte l'overflow sur long, i++ != fin est un peu plus simple) mais on ne peut pas dire que j'apprécie.

Code :
  1. for (i = debut, done = i > fin; !done; (i != fin && ++i) || (done = 1)) {
  2.    ...
  3. }

fonctionne aussi mais ne me plait pas plus.


Oui, quand je vois la solution je me dis "j'aurais pu trouver moi aussi" mais bon, j'aurais jamais penser à utiliser l'opérateur de concaténation pour shunter le fait que "i++" puisse donner 0. Bizarrement j'ai plus rapidement pigé la 2° soluce...
 
Ca m'a donné l'idée du truc suivant:  

Code :
  1. for (i=debut; ((i++ ?i :fin) != fin); /* nothing */)


Message édité par Sve@r le 09-08-2007 à 22:24:45

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1597989
matafan
Posté le 09-08-2007 à 22:25:41  profilanswer
 

C'est quand même plus simple d'ajouter un break en fin de boucle si i == fin.

n°1598233
Un Program​meur
Posté le 10-08-2007 à 15:24:40  profilanswer
 

matafan a écrit :

C'est quand même plus simple d'ajouter un break en fin de boucle si i == fin.


Montre ta solution complete.

n°1598338
Sve@r
Posté le 10-08-2007 à 17:13:08  profilanswer
 

Un Programmeur a écrit :


Montre ta solution complete.


 

i=debut;
while (1)
{
    ...
    if (i++ == fin) break;
}


   


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1598344
Un Program​meur
Posté le 10-08-2007 à 17:31:05  profilanswer
 

C'est pas vraiment different de

Code :
  1. i=debut;
  2. do {
  3.    ...
  4. } while (i++ == fin);

que j'avais cite si on acceptait l'overflow (ce que je ne fais pas parce que les optimiseurs se mettent a utiliser le fait qu'un overflow de nombres signes est un comportement indefini) mais sans le test qui empeche le passage dans la boucle quand debut > fin.

Code :
  1. if (debut <= fin) {
  2.    for(i = debut; 1; ++i) {
  3.       ...
  4.       if (i == fin) break;
  5.    }
  6. }


Mais on ne peut pas dire que ca m'enchante plus.  J'aime bien que tout le controle de la boucle soit dans le for.

Code :
  1. if (debut <= fin) {
  2.    i = debut;
  3.    while (1) {
  4.       ...
  5.       if (i == fin)
  6.          break;
  7.       ++i;
  8.    }
  9. }

Message cité 1 fois
Message édité par Un Programmeur le 10-08-2007 à 17:34:28
n°1598389
Sve@r
Posté le 10-08-2007 à 19:00:07  profilanswer
 

Un Programmeur a écrit :

C'est pas vraiment different de

Code :
  1. i=debut;
  2. do {
  3.    ...
  4. } while (i++ == fin);

que j'avais citée si on acceptait l'overflow


Ben l'exemple invoké par Matafan et que j'ai codé au dessus ne se préoccupe pas de l'overflow !!!

Un Programmeur a écrit :

Code :
  1. if (debut <= fin) {
  2.    for(i = debut; 1; ++i) {
  3.       ...
  4.       if (i == fin) break;
  5.    }
  6. }


Mais on ne peut pas dire que ca m'enchante plus.  J'aime bien que tout le controle de la boucle soit dans le for.


Ben ce que j'avais proposé juste avant était géré dans le for

Code :
  1. for (i=debut; ((i++ ?i :fin) != fin); /* nothing */)


 
Evidemment je joue sur l'overflow (qui était aussi l'idée de ma 2° boucle piège en début de topic). Mais ya pas de miracle. Si tu veux faire un "for" (où l'évaluation se fait en début de boucle), faut qu'en début de boucle tu aies gardé une trace de la boucle précédente. Si cette boucle précédente était la dernière qu'il aurait dû se passer alors tu rend l'évaluation fausse...
Ce qui nous ramène à ceci (issu de tes premières idées)

Code :
  1. for (i=debut, flag=1; flag == 1; flag=(i++ != fin ?1 :0))


Message édité par Sve@r le 10-08-2007 à 19:27:24

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

  [c] Question sur une boucle do...while

 

Sujets relatifs
Tri de réponses chiffre/caractère [resolu]problème boucle until
[shell script] Question sur l'init d'une variable[C++] question facile
Question cookie[MCD] Question au sujet d'une contrainte
Question sur les gridview[Javascript] Boucle for [résolu]
Problème boucle à droite!boucle if après find
Plus de sujets relatifs à : [c] Question sur une boucle do...while


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR