pratix
Messages postés11Date d'inscriptionlundi 10 février 2003StatutMembreDernière intervention12 mars 2003
-
24 févr. 2003 à 23:09
cs_Zipotron
Messages postés6Date d'inscriptiondimanche 27 juin 2004StatutMembreDernière intervention 8 octobre 2012
-
27 juin 2004 à 02:41
bonjour ,
suite aux conseils que l'on ma donné , j'ai revu un petit programme de recherche de nbr qui était assez compliqué pour ce qu'il avait à faire.
je lai simplifié mais je voudrai avoir votre avis sur la façon dont je reviens au début de mon prg.
Je rappelle la fonction main(), le pgr fonctionne trés bien
mais je ne sais pas si c'est une façon courante de procédé sinon qu'elle est la façon"normale" de revenir au début du prg.
merci.
Pratix
#include
#include <ctime>
#include <cstdlib>
using std::cout;
using std::cin;
using std::endl;
int Debut();
int NbrAleatoire();
void Compare(int,int);
void main()
{
int Alea=NbrAleatoire();
int _Chiffre=Debut();
Compare (_Chiffre, Alea);
return(0);
}
int Debut()
{
cout<<"Entrez un chiffre entre 1 et 500"<<endl;
int Chiffre;
cin>>Chiffre;
return (Chiffre);
}
int NbrAleatoire()
{
int Aleatoire;
srand(time(0)),Aleatoire=1+rand()%500;
return(Aleatoire);
}
void Compare( int _1Somme,int _Alea)
{
int Essai=0,o;
char z;
while(Essai!=8)
{
cs_vieuxLion
Messages postés455Date d'inscriptionsamedi 26 octobre 2002StatutMembreDernière intervention 6 avril 20048 24 févr. 2003 à 23:39
soir !
décidément, tu maltraite la fonction "main"
1) son prototype "officiel" est int main()
tu as écrit void main() suivi d'un return(0);
ce qui signifie retour effectif d'un int avec la déclaration de ne rien retourner
2) on ne rappelle pas "main"
on contrôle plutôt dans une boucle le désir de l'utilisateur de continuer, et sinon on laisse "main" se terminer (plutôt que d'employer exit)
jonathanmcdougall
Messages postés64Date d'inscriptiondimanche 9 février 2003StatutMembreDernière intervention 7 mars 2003 25 févr. 2003 à 06:45
> bonjour ,
> suite aux conseils que l'on ma donné , j'ai revu un petit
>programme de recherche de nbr qui était assez compliqué
>pour ce qu'il avait à faire.
>
> je lai simplifié mais je voudrai avoir votre avis sur la façon
>dont je reviens au début de mon prg.
>
> Je rappelle la fonction main(), le pgr fonctionne trés bien
> mais je ne sais pas si c'est une façon courante de procédé
>sinon qu'elle est la façon"normale" de revenir au début du
>prg.
Non. Comme j'en avais parlé, un programme doit fonctionner sous forme de boucle. Ton programme souffre de récursivité (maladie trèèèès contagieuse), c'est-à-dire que les fonctions s'appelent les unes les autres sans jamais en sortir. Tu empiles des assiettes sans arrêt et un jour cette pile tombera :
int f()
{
f();
}
Dans pas longtemps, tu auras une erreur de pile, tes assiettes se sont effondrées : f() ne se termine jamais, car il s'appelle à chaque fois avant s'être terminé! Tu fais la même chose : main() appelle Compare(), Compare() rappelle main(), main() rappelle Compare(), Compare() rerapelle main() et ainsi de suite. Ces fonctions NE SE TERMINENT JAMAIS, ELLES S'EMPILENT L'UNE SUR L'AUTRE, et ça mon ami, c'est mauvais.
Le principe est simple :
===
while (condition_quelconque)
{
déroulement du programme
}
fin du programme
====
C'est la seule manière efficace pour un programme de tourner. Voici cette boucle un peu plus adaptée à ton programme :
===
while ( true ) //boucle sans fin
{
// trouver un nombre au hasard
// demander un nombre à l'utilisateur
// vérifier ce nombre
// si c'est le bon, afficher un message
// s'il a dépassé le nombre d'essais maximal, afficher un
// message d'erreur
// dans ces deux cas, demander à l'utilisateur s'il veut
// recommencer (car il a bel et bien fini)
// s'il veut sortir, faire un break
// si ce n'est pas le bon, retourner en haut
}
// fin du programme
===
Ça commence déjà à prendre forme. Je suis sûr que tu as eu un déclic 'goto' quand tu as vu 'retourner en haut'. Eh bien reclic le déclic et fais lui prendre ses clics et ses clacs en deux temps trois clics. Ce n'est pas The C++ Way (ni The Modern Way, ni The Good Way, ni The Easy Way, ni The Efficient Way).
La solution, c'est (ce sont?) les boucles.
Voici le canevas du programme que je ferais :
===
/***** PROTOTYPES *****/
//retourne un nombre au hasard
unsigned int nombre_hasard();
//contient une boucle qui tourne tant que
// 1) l'utilisateur n'a pas gagné (trouvé le nombre)
// 2) l'utilisateur n'a pas perdu (trop d'essais)
//cette fonction retourne 'true' si l'utilsateur a gagné et 'false'
//s'il a perdu
bool demander_nombre();
//affiche un message de félicitation
void afficher_reussi();
//affiche un message de consolation
void afficher_perdu();
//demande à l'utilisateur s'il veut continuer
//retourne 'true' si oui et 'false' sinon
bool demander_continuer();
Aussi simple que ça. L'implémentation des fonctions est assez simple, sauf, peut-être, pour demander_nombre(). Voici un début :
===
bool demander_nombre()
{
while ( true ) //boucle sans fin (encore!)
{
// demander un nombre
// vérifier ce nombre
// s'il est bon, retourner 'true'
// s'il est mauvais, vérifier le nombre d'essais
// si le nombre d'essais est trop grand, retourner 'false'
// sinon... rien. On retourne en haut de la boucle
}
}
===
Tu vois? La boucle principale se charge de recommencer ou de terminer le programme. La boucle secondaire, dans demander_nombre(), se charge de 1 jeu à la fois. La boucle principale utilise sa valeur de retour pour juger quel message afficher.
Tu vois, en plus, la modularité? demander_nombre() ne dépend de personne. afficher_message() non plus et demander_continuer() non plus.
Voici maintenant un exemple avec une classe et la surcharge des opérateurs.
C'est une blague.
L'important c'est que tu t'amuses tout en apprenant. Voici, finalement, quelques commentaires sur le code :
> void Compare(int,int);
Je préfère mettre le nom des variables dans les déclarations de fonctions, c'est plus clair, mais ce n'est pas obligé.
> void main()
Je m'arrache les cheveux ici :) C'est 'int main()', pas 'void main()'.
> int _Chiffre=Debut();
Ce n'est pas grave, mais sache que les noms de variables qui commencent par un underscore (_) sont réservés à l'implémentation, c'est-à-dire aux librairies. Par exemple, les variables de ton commencent toutes par un _. C'est une convention qu'il est bon de suivre :
variable : ta variable à toi
variable_ : une variable membre d'une de tes classes
_variable : une variable qui fait partie d'une librairie distribuée
> return(0);
Correct, mais pas obligatoire. De plus, logiquement, tu ne devrais rien retourner puisque ton main() est défini comme étant 'void'... :)
> int NbrAleatoire()
> {
> int Aleatoire;
> srand(time(0)),Aleatoire=1+rand()%500;
> return(Aleatoire);
> }
Mmmm.. mauvais style. Syntaxiquement correct, mais difficilement lisible pour rien. Préférer quelque chose comme
srand(time(0));
return (1+rand()%500);
>
> void Compare( int _1Somme,int _Alea)
même chose ici pour _1Somme et _Alea.
> {
> int Essai=0,o;
Et ça, c'est quoi?? Sache que la virgule n'est que très rarement utilisée en C++ dans les expression (à part pour les for, je ne pense à rien pour le moment). Elle sert à évaluer les expressions de droite à gauche et de retourner celle le plus à gauche :
int a 8, 9, 10, 11; //a 8
De plus, si je vois bien, tu as mis un 'o' (prononcer 'eau') à droite de la virgule et ça ne devrait pas compiler (variable non définie, ou quelque chose comme ça).
> if(z!='o')
> {
> exit(0);
> }
> {
> main();
> }
C'est logique, mais pas correct. En utilisant une boucle, tu aurais pu retourner 'false' à la place faire un 'exit' (qui est à éviter, sauf en cas d'erreur fatale qui doit terminer le programme) et retourner un 'true' à la place de rappeler main() (qui ne devrait jamais se faire appeler à la main ('main' du genre celle au bout de ton bras, pas la fonction...), soit dit en passant). Ainsi, la fonction ayant appelée celle-ci pourrait alors décider quoi faire.
La morale de cette histoire est celle-ci (et c'est la plus importante de toutes) :
UNE FONCTION, UNE TÂCHE
Relis cette morale.
Encore.
Bien. Ta fonction NbreAleatoire() en retourne un et c'est sa seule tâche, et c'est bien.
Ta fonction Debut demande un chiffre à l'utilisateur. C'est sa seule tâche, et c'est bien encore.
Ta fonction Compare() a sept tâches.
1) Elle compare deux nombres (justement, c'est son nom).
2) Elle boucle
3) Elle affiche des messages
4) Elle signale que l'utilisateur a gagné
5) Elle signale que l'utilisateur a perdu
6) Elle demande pour sortir du programme
7) Elle sort du programme
Ce qui fait que, dans le meilleur des mondes, tu devrais avoir 6 fonctions de plus que celles que tu as déjà. C'est beaucoup, je sais. Mais peut-être pourrais-tu envisager d'en ajouter 2? Ou peut-être 3? Ça fragmenterais ton code et le rendrais plus lisible, plus efficace et plus réutilisable.
Si une fonction s'appelle Compare, elle doit comparer des nombres. Si elle s'appelle Debut, elle doit initialiser quelque chose. Si elle s'appelle NbreAleatoire, elle doit en générer un. Si tu n'est pas capable de trouver un nom pour une fonction, coupe la en deux. Si le nom que tu as trouvé est vague (du genre FaireRoulerProgramme()), t'as un problème. Une fonction de plus de 10 lignes est une mauvaise fonction.
pratix
Messages postés11Date d'inscriptionlundi 10 février 2003StatutMembreDernière intervention12 mars 2003 25 févr. 2003 à 12:52
Je savais que je fe faisais une co......, mais bon! j'ai essayer
avec des boucles ,mais je n'arrive pas au résultat que je veux, revenir au début du programme .
En tout cas, j'ai compris," pas de rappel de fonction ,mais des boucles" Je vais encore y passer quelques heures, et si c'est pas bon ,faudra me donner un coup de main qu'enfin je puisse dormir et ma copinne aussi (parce que assis dans le lit avec le portable...)
cs_Beuss
Messages postés100Date d'inscriptionsamedi 27 juillet 2002StatutMembreDernière intervention11 juin 2003 26 févr. 2003 à 15:00
Wé en gros tu dois demander à l'utilisateur si il veut continuer dans ton main
int main()
{
int Alea;
int _Chiffre;
do
{
Alea = NbrAleatoire();
Chiffre = Debut();
Compare(_Chiffre, Alea);
cout << "Voulez vous continuer (o/n) ? ";
cin >> rep;
}
while(toupper(rep) != 'O');
}
et tu le vire de la fonction compare. quand on te dit ca va planter vite fait C une facon de parler, j'ai testé un main reccursif ca plante au bout de 12000 appels mais ca dépend de ton nombre de variable et de toute facon C pas beau et C pas bien la récursivité
cs_Beuss
Messages postés100Date d'inscriptionsamedi 27 juillet 2002StatutMembreDernière intervention11 juin 2003 27 févr. 2003 à 13:53
C'est bien mais t'as fait un peu long et surtout c'est pas propre du tout, tu utilises des break alors qu'il n'y en a pas besoin, la condition dans les boucles elle est faite pour etre utilisée...
jonathanmcdougall
Messages postés64Date d'inscriptiondimanche 9 février 2003StatutMembreDernière intervention 7 mars 2003 27 févr. 2003 à 22:56
> C'est bien mais t'as fait un peu long et surtout c'est pas
>propre du tout, tu utilises des break alors qu'il n'y en a pas
>besoin, la condition dans les boucles elle est faite pour etre
>utilisée...
Hmmm. Que penses-tu de ça?
while (true)
{
a();
b();
if (valeur) break;
c();
d();
}
Moi, à part mettre c() et d() dans le if, je ne vois pas d'autre solution, mais cette solution ne s'applique pas, car je n'ai écris ici qu'un exemple académique. Une boucle plus complexe pourrait avoir plusieurs possibilités de sortie.
Il existe plusieurs occasions où la structure la plus efficace est une boucle sans fin dans laquelle plusieurs conditions sont testées. Mais j'avoue que pour le code que j'ai présenté, la condition aurait été équivalente (et non pas, à mon avis, plus 'propre').
cs_Beuss
Messages postés100Date d'inscriptionsamedi 27 juillet 2002StatutMembreDernière intervention11 juin 2003 27 févr. 2003 à 23:01
wiwiwi mais bon j'aime bien dire plus propre et pis j'étais un peu de mauvaise humeur et j'ai un prof d'algo qui aime pas utiliser des instructions là où il n'y en a pas besoin ;)
voilou :p