IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

calculatrice polonaise inversée (K&R)


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2022
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2022
    Messages : 19
    Par défaut calculatrice polonaise inversée (K&R)
    Bonjour,
    je débute en C. Je lis le K&R. À la page 75, on implémente une calculatrice basique. Il y a des choses qui m'échappent.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
     
    #define MAXOP 100	/* taille maximale d'un opérande ou d'un opérateur */
    #define NOMBRE '0'	/* indique que l'on a lu un nombre */
     
    int lire_op(char []);
    void empiler(double);
    double depiler(void);
     
    /* calculatrice en polonaise inversée */
    int main()
    {
    	int type;
    	double op2;
    	char s[MAXOP];
     
    	while ((type = lire_op(s)) != EOF) {
    		switch(type) {
    			case NOMBRE:
    				empiler(atof(s));
    				break;
    			case '+':
    				empiler(depiler() + depiler());
    				break;
    			case '*':
    				empiler(depiler() * depiler());
    				break;
    			case '-':
    				op2 = depiler();
    				empiler(depiler() - op2);
    				break;
    			case '/':
    				op2 = depiler();
    				if (op2 != 0.0)
    					empiler(depiler() / op2);
    				else
    					printf("erreur : division par zéro\n");
    				break;
    			case '\n':
    				printf("\t%.8g\n", depiler());
    				break;
    			default:
    				printf("erreur : commande inconnue %s\n", s);
    				break;
     
    		}
    	}
    	return 0;
    }
     
    #define MAXVAL 100	/* profondeur maxi de la pile val */
    int pp = 0;			/* prochaine position libre de la pile */
    double val[MAXVAL];	/* pile de valeurs */
     
    /* empiler : place f au sommet de la pile de valeurs */
    void empiler(double f)
    {
    	if (pp < MAXVAL)
    		val[pp++] = f;
    	else
    		printf("pile pleine, impossible d'empiler %g\n", f);
    }
     
    /* depiler : extrait et retourne la valeur du sommet de la pile */
    double depiler(void)
    {
    	if (pp > 0)
    		return val[--pp];
    	else {
    		printf("erreur : pile vide\n");
    		return 0.0;
    	}
    }
     
    int lirecar(void);
    void remettrecar(int);
     
    /* lire_op : lit le prochain opérateur ou opérande numérique */
    int lire_op(char s[])
    {
    	int i, c;
     
    	while ((s[0] = c = lirecar()) == ' ' || c == '\t')
    		;
    	s[1] = '\0';
    	if (!isdigit(c) && c != '.')
    		return c;		/* pas un nombre */
    	i = 0;
    	if (isdigit(c))		/* lire la partie entière */
    		while (isdigit(s[++i] = c = lirecar()))
    			;
    	if (c == '.')		/* lire la partie fractionnaire */
    		while (isdigit(s[++i] = c = lirecar()))
    			;
    	s[i] = '\0';
    	if (c != EOF)
    		remettrecar(c);
    	return NOMBRE;
    }
     
    #define TAILLETAMP 100
     
    char tamp[TAILLETAMP];		/* tampon pour remettrecar */
    int ptamp = 0;				/* prochaine position libre dans tamp */
     
    int lirecar(void)			/* lit un caractère (éventuellement remis sur l'entrée) */
    {
    	return (ptamp > 0) ? tamp[--ptamp] : getchar();
    }
     
    void remettrecar(int c)		/* remet c sur l'entrée */
    {
    	if (ptamp >= TAILLETAMP)
    		printf("remettrecar : trop de caractères\n");
    	else
    		tamp[ptamp++] = c;
    }
    Lorsque je tape CTRL+D (je suis sur Mac), la fonction lire_op renvoie -1 et on quitte la boucle while. En revanche, si je tape a (par exemple) suivi de CTRL+D, le terminal affiche
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    erreur : commande inconnue a
    , mais en revanche on ne quitte pas la boucle while juste après (ce que je ne comprends pas).
    Par avance merci pour vos explications.

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Rasko Voir le message
    Lorsque je tape CTRL+D (je suis sur Mac), la fonction lire_op renvoie -1 et on quitte la boucle while. En revanche, si je tape a (par exemple) suivi de CTRL+D, le terminal affiche
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    erreur : commande inconnue a
    , mais en revanche on ne quitte pas la boucle while juste après (ce que je ne comprends pas).
    Le ctrl-d n'est pas enregistré comme un caractère "à lire", c'est une interruption système. Elle symbolise "fin de fichier" (en C tout périphérique IO est vu comme un fichier) mais à condition qu'elle soit seule sur la ligne. Si elle suit un caractère alors elle n'est pas prise en compte.
    Dans ton programme si tu entres "4 5 +" ça ressort "9" mais si tu entres 4 5 ctrl-d +" ça sort aussi 9. Si le ctrl-d n'est pas seul, alors il est "shunté" par l'OS et le programme ne le voit pas. Et s'il est seul, alors l'OS envoie l'interruption au programme qui la traduit par "lecture terminée".
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2022
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2022
    Messages : 19
    Par défaut
    Merci pour votre réponse. Tout n'est pas encore très clair pour moi. Lorsque je tape "a CTRL+D", il y a une interruption qui provoque l'affichage "erreur : commande inconnue a", sans toutefois quitter la boucle. En revanche, si je tape "1 CTRL+D", il n'y a pas d'interruption (le symbole "^D" apparaît sur la ligne courante).
    Par ailleurs, si le CTRL+D n'est pas pris en compte, je ne comprends pas l'intérêt des lignes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     if (c != EOF)
    	remettrecar(c);
    dans le corps de la fonction lire_op.
    Désolé si mes questions ne sont pas claires, tout cela est vraiment confus pour moi.

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Rasko Voir le message
    Lorsque je tape "a CTRL+D", il y a une interruption qui provoque l'affichage "erreur : commande inconnue a", sans toutefois quitter la boucle. En revanche, si je tape "1 CTRL+D", il n'y a pas d'interruption
    Dans ton programme, "a" + ctrl-d équivaut à "a" + <return>. Le "ctrl-d" valide la saisie. Or pour la calculatrice, "a" est une commande inconnue.
    Dans ce même programme, "1" + ctrl-d équivaut à un simple "1", le ctrl-d ne valide rien, n'est pas pris en compte. Il faut en effet rajouter explicitement <return> pour valider. On peut toutefois, après avoir tapé "ctrl-d" (non pris en compte) insérer d'autres chiffre (ex "2", "3") avant de valider via <return>. Le "ctrl-d" n'est réellement pas pris en compte puisque "12" + ctrl-d + "3" est vu comme "123".
    Et si au lieu de mettre "2" ou "3" on met un "a" et qu'on rajoute un ctrl-d alors le ctrl-d cette fois valide la saisie (se comporte comme <return>) et le programme sort une erreur puisqu'effectivement "1a" n'est pas une commande reconnue.

    Alors pourquoi dans un cas "ctrl-d" valide et dans un autre cas il ne valide pas, j'en sais rien. Il me faudrait examiner le code plus en détail pour le comprendre. Peut-être effectivement c'est le rôle de cette instruction if (c != EOF) remettrecar(c). Mais cela ne change rien au fait que ctrl-d ne signifie "EOF" que s'il est seul sur sa ligne. Exactement comme pour le service smtp qui attend, pour envoyer le mail, qu'on termine la saisie par un simple "point" seul sur sa ligne.

    Donc pas compliqué à comprendre: tu veux que ton programme valide le test "EOF" tu lui envoies un "ctrl-d" tout seul. Si le "ctrl-d" n'est pas tout seul, alors la fonction de lecture ne renvoie pas "EOF" donc le programme considère qu'il a lu des trucs. A partir de là ce qu'il fait dépend fatalement de ce qu'il a lu et des actions programmées en conséquence.

    Citation Envoyé par Rasko Voir le message
    (le symbole "^D" apparaît sur la ligne courante).
    Juste un effet d'affichage. Je pense que tu es sous zindow. Sous Linux, par exemple, il n'apparait absolument rien.

    Citation Envoyé par Rasko Voir le message
    Par ailleurs, si le CTRL+D n'est pas pris en compte, je ne comprends pas l'intérêt des lignes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     if (c != EOF)
    	remettrecar(c);
    dans le corps de la fonction lire_op.
    Pareil, il faudrait dérouler l'algo à la main pour le comprendre. Quand on l'enlève, si on tape "123a" + ctrl-d il ne se passe rien, il faut rajouter un second "ctrl-d" pour que la commande soit prise en compte.

    Citation Envoyé par Rasko Voir le message
    Désolé si mes questions ne sont pas claires, tout cela est vraiment confus pour moi.
    Le mieux pour comprendre c'est partir sur un code plus simple qui ne fait que lire et afficher. Parce qu'effectivement là tu tentes de comprendre un algo qui doit analyser la syntaxe NPI et aussi gérer les effets des caractères de contrôle (ctrl-d, ctrl-c, etc). Partir d'un code plus simple dans lequel il n'y a pas surcharge d'instructions destinées à analyser ce qui est lu permettra de mieux cerner les choses.

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <stdio.h>
     
    int main() {
    	int c;
    	while (1) {
    		c=fgetc(stdin);
    		printf("c=[%c] [%x]\n", c, c);
    		if (c == EOF) break;
    	}
    }
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 770
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 770
    Par défaut
    Je n'ai pas compilé ton code mais SVP lis ton code

    Lorsque tu saisis "a CTRL+D", la lettre a est interprétée : dans ton switch c'est le cas par défaut, la mauvaise saisie "erreur : commande inconnue". Et ensuite, CTRL+D est pris en compte : interruption.
    Lorsque tu saisis "1 CTRL+D", la fonction atof (dans empiler(atof(s));) va prendre que les chiffres du début (donc 1), et abandonner le reste de la saisie. Donc 1 est empilé, et CTRL+D ignoré.

    atof, documentation cplusplus.com en anglais

  6. #6
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par foetus Voir le message
    Lorsque tu saisis "a CTRL+D", la lettre a est interprétée : dans ton switch c'est le cas par défaut, la mauvaise saisie "erreur : commande inconnue". Et ensuite, CTRL+D est pris en compte : interruption.
    Non, pas interruption, un ctrl-d qui n'est pas seul n'est pas pris en compte. Donc le programme affiche "a commande inconnue" et reboucle à la saisie suivante.
    Sinon bien vu le atof().
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. Interpréteur Notation Polonaise Inverse
    Par arkhamon dans le forum Contribuez
    Réponses: 0
    Dernier message: 27/02/2010, 14h59
  2. Réaliser calculatrice polonaise inversée
    Par hana.90 dans le forum C
    Réponses: 2
    Dernier message: 03/02/2009, 01h28
  3. Réponses: 6
    Dernier message: 02/11/2008, 11h57
  4. Calculatrice polonaise - Utilisation des piles
    Par romero2008 dans le forum Pascal
    Réponses: 3
    Dernier message: 01/05/2008, 15h35
  5. construire 1 arbre pour une calculatrice polonaise prefixée
    Par AliJava dans le forum Algorithmes et structures de données
    Réponses: 7
    Dernier message: 21/02/2008, 00h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo