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

Question sur une boucle do...while [c] - C - Programmation

Marsh Posté le 08-08-2007 à 09:55:44    

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 ) ;

Reply

Marsh Posté le 08-08-2007 à 09:55:44   

Reply

Marsh Posté le 08-08-2007 à 10:00:17    

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

Reply

Marsh Posté le 08-08-2007 à 11:33:52    

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]

Reply

Marsh Posté le 08-08-2007 à 19:34:28    

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.
Reply

Marsh Posté le 09-08-2007 à 09:19:36    

Dans le genre piege:
 

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

Reply

Marsh Posté le 09-08-2007 à 09:50:47    

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

Reply

Marsh Posté le 09-08-2007 à 10:16:45    

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.
Reply

Marsh Posté le 09-08-2007 à 10:22:29    

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.

Reply

Marsh Posté le 09-08-2007 à 10:48:30    

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.
Reply

Marsh Posté le 09-08-2007 à 11:24:19    

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 ;)

Reply

Marsh Posté le 09-08-2007 à 11:24:19   

Reply

Marsh Posté le 09-08-2007 à 11:49:22    

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.
Reply

Marsh Posté le 09-08-2007 à 13:05:55    

[:azitwaz]

Reply

Marsh Posté le 09-08-2007 à 14:17:03    

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. }

Reply

Marsh Posté le 09-08-2007 à 14:30:21    

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)

Reply

Marsh Posté le 09-08-2007 à 14:33:11    

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.
Reply

Marsh Posté le 09-08-2007 à 14:57:20    

Et si fin = LONG_MAX ?

Reply

Marsh Posté le 09-08-2007 à 15:22:30    

Facile, tu passes en long long ;)

Reply

Marsh Posté le 09-08-2007 à 16:33:37    

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.
Reply

Marsh Posté le 09-08-2007 à 16:51:21    

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.

Reply

Marsh Posté le 09-08-2007 à 17:24:45    

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.
Reply

Marsh Posté le 09-08-2007 à 17:41:51    

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

Reply

Marsh Posté le 09-08-2007 à 20:23:50    

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.
Reply

Marsh Posté le 09-08-2007 à 21:35:07    

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
Reply

Marsh Posté le 09-08-2007 à 22:22:52    

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.
Reply

Marsh Posté le 09-08-2007 à 22:25:41    

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

Reply

Marsh Posté le 10-08-2007 à 15:24:40    

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.

Reply

Marsh Posté le 10-08-2007 à 17:13:08    

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.
Reply

Marsh Posté le 10-08-2007 à 17:31:05    

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
Reply

Marsh Posté le 10-08-2007 à 19:00:07    

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.
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed