Aller au menu - Aller au contenu

Exercices pour débutants en C

Au menu : zSommeChiffres (nombres, algo)

Pour accéder à cette section
Connectez-vous !
connexion_rpx
Page Précédente  1  2  3  ...  11  12  13  14  15  16  17  ...  50  51  52  53  Suivante
Auteur Message
1 visiteur sur ce sujet (1 Anonyme)
Page Précédente  1  2  3  ...  11  12  13  14  15  16  17  ...  50  51  52  53  Suivante
Hors ligne candide # Posté le 20/12/2008 à 16:37:17
"In C ode we trust"
Avatar

Reprise du dernier message de la page précédente :
Citation : crys'

L'objectif de cet exercice est de réaliser un calculateur d'expressions sous la forme NPI (notation polonaise inverse) en vous servant des piles. Vous devez donc vous imaginer un algorithme qui permettrait d'évaluer un calcul en NPI en retournant le résultat.


Comme d'habitude le spécification sont assez vagues. Le programmeur est-il censé donner une expression valide ? Sous quelle forme apparaissent les entrées, ce n'est pas anodin du tout à cause des nombres négatifs (cf. ci-dessous) ? L'obligation d'utiliser une pile est une contrainte dictée par la tradition mais on peut s'en abstenir me semble-t-il.


Sinon, je trouve l'exercice mal choisi, cf. le titre du post : "Exercices pour débutants en C". C'est beaucoup plus un exercice sur les structures de données et d'algorithmique qu'un exercice de codage en C, ce qui est au bout du compte dans ce zExo la partie la plus facile.

Par ailleurs, l'exercice en soi est difficile pour des débutants. La preuve ? toute simple : le code dans K&R qui implémente cette question (§5.10 Command-line Arguments) est très long : environ 125 lignes mais une ligne de C de K&R vaut 3 à 5 lignes chez le débutant, donc on va compter 500 lignes et Kernighan est un maitre en algorithmique donc le codage du débutant sera encore plus long. Noter que les formules doivent tenir dans des tableaux statiques ce qui un grosse limitation et dont la résolution nécessiterait encore plus de lignes de code.

Et le pire, ils se sont plantés. D'abord, une formule qui marche :


Code : C
1
2
3
candide@candide-desktop:~$ ./x
3 5 + 4 * 2 -
	30


Maintenant deux hics :

1°) le programme ne gère pas les formules invalides et pire il répond quelque chose :

Code : C
1
2
3
candide@candide-desktop:~$ ./x
100000 1 1 * + 1 1 1 + +
	3


2°) Absolument incroyable, le programme ne sait pas gérer les nombre négatifs et le passage à l'opposé, exemple :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
candide@candide-desktop:~$ ./x
2 3 + -
error: stack empty
	-5
2 3 + - 2 3 + - *
error: stack empty
error: stack empty
	-0
2 -3 -
error: stack empty
	-5


Le code de K&R :


Secret (cliquez pour afficher)
Code : C
  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
121
122
123
124
125
126
#include <stdio.h>
#include <stdlib.h> /* for atof() - in K&R, math.h is referenced - this is an anachronism */

#define MAXOP 100 /* max size of operand or operator */
#define NUMBER '0' /* signal that a number was found */

int getop(char []);
void push(double);
double pop(void);

/* reverse Polish calculator */

int main(void)
{
  int type;
  double op2;
  char s[MAXOP];

  while((type = getop(s)) != EOF)
  {
    switch(type)
    {
      case NUMBER:
        push(atof(s));
        break;
      case '+':
        push(pop() + pop());
        break;
      case '*':
        push(pop() * pop());
        break;
      case '-':
        op2 = pop();
        push(pop() - op2);
        break;
      case '/':
        op2 = pop();
        if(op2 != 0.0)
          push(pop() / op2);
        else
          printf("error: zero divisor\n");
        break;
      case '\n':
        printf("\t%.8g\n", pop());
        break;
      default:
        printf("error: unknown command %s\n", s);
        break;
    }
  }

  return 0;
}

#define MAXVAL  100 /* maximum depth of val stack */

int sp = 0; /* next free stack position */
double val[MAXVAL]; /* value stack */

/* push: push f onto value stack */
void push(double f)
{
  if(sp < MAXVAL)
    val[sp++] = f;
  else
    printf("error: stack full, can't push %g\n", f);
}

/* pop: pop and return top value from stack */
double pop(void)
{
  if(sp > 0)
    return val[--sp];
  else
  {
    printf("error: stack empty\n");
    return 0.0;
  }
}

#include <ctype.h>

int getch(void);
void ungetch(int);

/* getop: get next operator or numeric operand */
int getop(char s[])
{
  int i, c;

  while((s[0] = c = getch()) == ' ' || c == '\t')
    ;

  s[1] = '\0';
  if(!isdigit(c) && c != '.')
    return c; /* not a number */
  i = 0;
  if(isdigit(c)) /* collect integer part */
    while(isdigit(s[++i] = c = getch()))
      ;
  if(c == '.')
    while(isdigit(s[++i] = c = getch()))
      ;
  s[i] = '\0';
  if(c != EOF)
    ungetch(c);
  return NUMBER;
}

#define BUFSIZE 100

char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buf */

int getch(void) /* get a (possibly pushed back) character */
{
  return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c) /* push character back on input */
{
  if(bufp >= BUFSIZE)
    printf("ungetch: too many characters\n");
  else
    buf[bufp++] = c;
}




Au passage, tout ceci me confirme que, malgré tout ce qu'on dit (et surtout qu'on répète sans avoir vérifié par soi-même), le K&R est un livre bâclé (et j'aurais de nombreux autres exemples à donner).

Bref, ton exercice me semble totalement inadapté et c'est d'autant plus clair qu'il faisait suite à un exercice quasi-trivial qui avait donné peu de réponses et juste avant un exo super facile sur les tris élémentaires et qui avaient été considérés par toi meme comme difficile (je ne me souviens plus du terme exact).

Choisir des exercices ainsi que exemples adaptés à ceux à qui on veut enseigner quelque chose est tâche hautement difficile et c'est en partie à cause de la mauvaise réalisation de cette tâche que l'apprentissage du C est difficile.

Une fois de plus, ce ne seront pas les débutants qui répondront substantiellement à cet exo, c'est à craindre en tous cas.



 
Hors ligne zx-spectrum # Posté le 20/12/2008 à 20:11:01
http://www.worldofspectrum.org
Avatar

Bonjour Candide,
il est toujours difficile de proposer quelque chose. Je reconnais pour ma part que cet exo est particulièrement "hardu", et pas forcément à la portée du réel débutant.....
Neamoins, vu que personne se manifeste pour savoir ce que propose Chrys est à leur portée, donc pas de feedback, je pense qu'il fait ce qu'il peut pour nous contenter......
Pour ma part et cela n'engage que moi, j'encourage chrys à continuer à nous proposer des exos. S'ils ne sont pas adaptés à notre niveau, a nous a nous manifester, car j'ai pas vu de zeros comme moi dire : ah halte , je n'arrive pas à suivre.....
Ensuite à chacun à faire un effort, et au moins essayer à faire quelque chose, a proposer sa solution.
@+
Hors ligne L'Ombre Blanche # Posté le 21/12/2008 à 15:08:49
Hommage à Ewilan.
Avatar

Ville : Lyon
Pays : France métropolitaine

Citation : de zx-spectrum
S'ils ne sont pas adaptés à notre niveau, a nous a nous manifester, car j'ai pas vu de zeros comme moi dire : ah halte , je n'arrive pas à suivre.....
Ensuite à chacun à faire un effort, et au moins essayer à faire quelque chose, a proposer sa solution.

Si, je l'ai dit, et je crois que mon appel à été pris en compte.
Édité le 21/12/2008 à 15:09:51 par L'Ombre Blanche

Avec du temps, rien n'est impossible.

Sans rancune hein? ;) : Lien
 
Hors ligne shareman # Posté le 21/12/2008 à 15:46:08
charlotte <3
Avatar

Ville : Mertzwiller
Pays : France métropolitaine

Le prochain exercice sera très simple (et donc collera avec le titre). ^^ J'ai déjà rédigé l'énoncé.

Nouvel atelier : Codez votre propre petit préprocesseur pour langage C !
Citation : Woody Allen
Si l'au-delà existe, c'est à quelle distance du centre ville, et c'est ouvert jusqu'à quelle heure ?
 
Connecté yoch # Posté le 21/12/2008 à 18:02:25
Avatar

Citation : candide
Par ailleurs, l'exercice en soi est difficile pour des débutants. La preuve ? toute simple : le code dans K&R qui implémente cette question (§5.10 Command-line Arguments) est très long : environ 125 lignes mais une ligne de C de K&R vaut 3 à 5 lignes chez le débutant, donc on va compter 500 lignes et Kernighan est un maitre en algorithmique donc le codage du débutant sera encore plus long. Noter que les formules doivent tenir dans des tableaux statiques ce qui un grosse limitation et dont la résolution nécessiterait encore plus de lignes de code.

A mon avis, ce genre de preuve n'est pas valable : le nombre de lignes de code n'est aucunement indice de difficulté.

Et puis, n'oublions pas l'énoncé :
Citation : Pas de titre
Pour la dernière question, utiliser seulement les chiffres dans vos calculs et non les nombres à plus d'un chiffre. Pour lire un nombre dans une chaîne, c'est déjà un algorithme tout à part (pas très dur mais faites juste ce qui est demandé), tandis que récupérer un chiffre est très simple (on n'a même pas à réfléchir) et vous aurez tout le temps pour vous concentrer sur l'algorithme de lecture d'expressions en NPI, ce qui est le but de l'exercice.


Citation : candide
Et le pire, ils se sont plantés.
[...]

Maintenant deux hics :

1°) le programme ne gère pas les formules invalides et pire il répond quelque chose :

Code : C
1
2
3
candide@candide-desktop:~$ ./x
100000 1 1 * + 1 1 1 + +
	3


2°) Absolument incroyable, le programme ne sait pas gérer les nombre négatifs et le passage à l'opposé, exemple :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
candide@candide-desktop:~$ ./x
2 3 + -
error: stack empty
	-5
2 3 + - 2 3 + - *
error: stack empty
error: stack empty
	-0
2 -3 -
error: stack empty
	-5



Je suis d'accord, ces erreurs sont assez stupéfiantes (pour le passage a l'opposé, encore fallait-il savoir que c'est autorisé, mais pour le reste... a moins que le code ne vise d'autres objectif que la précision algorithmique, et encore !).

Maintenant, tout cela est en dehors du cadre de l'exercice tel que défini par l'énoncé, qui était très simple je trouve, et assez instructif globalement (pile, npi).

Vis a vis de la simplicité du code dans les cas un peu plus complets que demandé, je trouve que le conseil que j'avais donné (utiliser strtol) était excellent. Voici mon code (les espaces font office de séparateurs, gère les nombres négatifs, gère les erreurs : expression invalide, division par zéro) :

Secret (cliquez pour afficher)

Code : C
  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
#include <stdio.h>
#include <stdlib.h>

/** implémentation de pile provenant du tuto de Octal
http://www.siteduzero.com/tutoriel-3-34229-les-piles-et-les-files.html */

typedef struct pile
{
    int value;
    struct pile *precedent;
} Pile;

void pile_push (Pile **p_pile, int value)
{
    Pile *p_nouveau = malloc(sizeof *p_nouveau);
    if (p_nouveau != NULL)
    {
        p_nouveau->value = value;
        p_nouveau->precedent = *p_pile;
        *p_pile = p_nouveau;
    }
}

int pile_pop (Pile **p_pile)
{
    int ret = 0;
    if (*p_pile != NULL)
    {
        Pile *temporaire = (*p_pile)->precedent;
        ret = (*p_pile)->value;
        free(*p_pile), *p_pile = NULL;
        *p_pile = temporaire;
    }
    return ret;
}

void pile_clear(Pile **p_pile)
{
    while (*p_pile != NULL)
    {
        pile_pop(p_pile);
    }
}
/*********************************************************/

int isOperator (char c)
{
    return (c == '+' || c == '-' || c == '*' || c == '/');
}

int main(void)
{
    Pile *pile = NULL;
    char str[] = "-4 5 * -10 +";
    char *expr = str, *ptr;
    int a, b, val;
    /* compteur pour l'etat de la pile */
    int n = 0, divisionParZero = 0;

    do
    {
        val = strtol (expr, &ptr, 10);
        /* si strtol a lu un nombre */
        if ( expr < ptr )
        {
            expr = ptr;
            pile_push (&pile, val);
            n++;
        }
        /* sinon si on lit un operateur */
        else if ( isOperator (*expr) )
        {
            a = pile_pop(&pile);
            b = pile_pop(&pile);
            switch (*expr)
            {
            case '+':
                pile_push (&pile, b + a);
                break;
            case '-':
                pile_push (&pile, b - a);
                break;
            case '*':
                pile_push (&pile, b * a);
                break;
            case '/':
                if (a != 0)
                    pile_push (&pile, b / a);
                else
                    divisionParZero = 1;
                break;
            }
            n--;
        }
    }
    while (*++expr && !divisionParZero);

    /* Si la pile contient un seul element */
    if (n == 1 && !divisionParZero)
    {
        printf ("'%s' vaut : %d\n", str, pile_pop(&pile));
    }
    else
    {
        if (divisionParZero)
        {
            puts("Erreur : division par zero !");
        }
        else
        {
            puts("Erreur : l'expression est erronnee !");
        }
        /* On vide la pile */
        pile_clear(&pile);
    }
    return 0;
}

EDIT : ajout de la gestion de division par zéro.
Édité le 21/12/2008 à 18:48:10 par yoch
 
Hors ligne zx-spectrum # Posté le 21/12/2008 à 19:36:45
http://www.worldofspectrum.org
Avatar

Citation : L'Ombre Blanche
Citation : de zx-spectrum
S'ils ne sont pas adaptés à notre niveau, a nous a nous manifester, car j'ai pas vu de zeros comme moi dire : ah halte , je n'arrive pas à suivre.....
Ensuite à chacun à faire un effort, et au moins essayer à faire quelque chose, a proposer sa solution.

Si, je l'ai dit, et je crois que mon appel à été pris en compte.

Ok , je te rassure on est au moins deux alors :
!
@+
Hors ligne candide # Posté le 21/12/2008 à 22:56:13
"In C ode we trust"
Avatar

Citation : yoch

A mon avis, ce genre de preuve n'est pas valable : le nombre de lignes de code n'est aucunement indice de difficulté.


Bien sûr que si. En général, un programme de 500 lignes est plus complexe (!= difficile) qu'un programme qui en fait 30. Bien sûr je parle dans les cas usuels, pas de code de l'IOCCC. Ce qui ne veut pas dire que certains codes astucieux et très travaillés de 30 lignes soient moins faciles à concevoir que des codes faisant la même chose en 100 lignes.

Citation : yoch

Et puis, n'oublions pas l'énoncé :

Quel rapport ? Ce que le code de K&R fait, c'est exactement la même chose (la seule différence étant qu'on prend des nombres à un chiffre dans le zExo sinon, c'est pareil : npi et pile).

Citation : yoch

Voici mon code (les espaces font office de séparateurs, gère les nombres négatifs, gère les erreurs : expression invalide, division par zéro) :


Et tu crois que n'importe quel débutant va déjà simplement comprendre ton code ? Ton code est très difficile, il nécessite la maitrise de pas mal de choses non triviales en C, c'est du code ABOUTI, le contraire de ce que sait faire un débutant.


Par ailleurs, ton programme, à l'entrée invalide :
Code : Autre
1
2 3 + - 2 3 +


répond 5.

Voici le code que je propose :

Secret (cliquez pour afficher)
Code : C
 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
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  char *p = "1 2 + 3 4 * 1 5 3 2 - * - 2 * + 1 * - 3 -",*q=p;
  int pile[100] = { 0 };
  int hauteur = 0;

  while (*p)
    {
      switch (*p)
        {
        case ' ':
          break;
        case '+':
          pile[hauteur - 2] += pile[hauteur - 1];
          hauteur--;
          break;
        case '-':
          pile[hauteur - 2] -= pile[hauteur - 1];
          hauteur--;
          break;
        case '*':
          pile[hauteur - 2] *= pile[hauteur - 1];
          hauteur--;
          break;
        case '/':
          if (pile[hauteur] == 0)
            return 0;
          else
            {
              pile[hauteur - 2] /= pile[hauteur - 1];
              hauteur--;
            }
          break;
        default:
          pile[hauteur] = *p - '0';
          hauteur++;
        }
      p++;
    }

  printf("%s vaut %d\n", q, pile[0]);
  return 0;
}

Code : Console
1 2 + 3 4 * 1 5 3 2 - * - 2 * + 1 * - 3 - vaut -4


Mon code ne gère pas les expressions invalides (mais ce n'est pas très difficile à ajouter).

Édité le 21/12/2008 à 22:57:20 par candide


 
Hors ligne smail26 # Posté le 22/12/2008 à 09:12:07

salut tout le monde moi aussi je participerai à ce sujet car je veux bien apprendre le C
Hors ligne stallaf # Posté le 22/12/2008 à 09:50:25
intuitu personae
Avatar

Citation : Crys
Exercices pour débutants en C
Citation : smail26
...moi aussi je participerai à ce sujet car je veux bien apprendre le C


Et bien, entre des discours de gourous d'experts et des interventions de boulets p'tits nouveaux, comment un débutant peut-il s'y retrouver ? :lol:

Gourou, tu deviendras...
 
Hors ligne candide # Posté le 22/12/2008 à 10:30:20
"In C ode we trust"
Avatar

Citation : stallaf
Citation : Crys
Exercices pour débutants en C
Citation : smail26
...moi aussi je participerai à ce sujet car je veux bien apprendre le C


Et bien, entre des discours de gourous d'experts et des interventions de boulets p'tits nouveaux, comment un débutant peut-il s'y retrouver ? :lol:


Comme quoi, ce n'est pas si évident de proposer les bons exercices d'apprentissage adaptés au public visé, c'est même un vrai boulot, ça s'appelle enseignant et meme les enseignants ne parviennent pas souvent à un résultat satisfaisant. La production d'un petit exo facile pour débutant peut nécessiter des heures de conception, mais tout dépend du degré de rigueur du concepteur.

Ici, les exos sont des difficultés inégales, ils s'adressent à un public au savoir trop indéterminé, leur contenu hésite trop entre codage C et algorithmique. Et la rubrique n'a pas encore réussi à fidéliser un public substantiel de zéros, à la différence par exemple du vrai succès des sujets de Nanoc (qui sont en C++ mais c'est dommage qu'il n'y ait pas la meme rubrique mais en C). AMHA, si les zexos veulent cibler un public de débutants, il faut absolument limiter la difficulté de ces exercices, éviter toute question d'algorithmique pure, soigner les spécifications et surveiller la précision des énoncés.


 
Hors ligne zx-spectrum # Posté le 22/12/2008 à 10:37:46
http://www.worldofspectrum.org
Avatar

Citation : stallaf
Citation : Crys
Exercices pour débutants en C
Citation : smail26
...moi aussi je participerai à ce sujet car je veux bien apprendre le C


Et bien, entre des discours de gourous d'experts et des interventions de boulets p'tits nouveaux, comment un débutant peut-il s'y retrouver ? :lol:

-sauf que les petits nouveaux je n'en ai vu que deux qui se manifestent...
-le discours de gourous comme tu dis, heureusement qu'ils sont la pour nous faire progresser, il suffit juste a un moment donné de leur signaler : stop j'ai rien compris, explications supplémentaires requises, et ils le font (merci au passage pour eux)

Le repérage me parait aisé pour les nouveaux, il suffit de réaliser les deux points ci-dessus.


Citation : candide
Comme quoi, ce n'est pas si évident de proposer les bons exercices d'apprentissage adaptés au public visé, c'est même un vrai boulot, ça s'appelle enseignant et meme les enseignants ne parviennent pas souvent à un résultat satisfaisant. La production d'un petit exo facile pour débutant peut nécessiter des heures de conception, mais tout dépend du degré de rigueur du concepteur.

Ici, les exos sont des difficultés inégales, ils s'adressent à un public au savoir trop indéterminé, leur contenu hésite trop entre codage C et algorithmique. Et la rubrique n'a pas encore réussi à fidéliser un public substantiel de zéros, à la différence par exemple du vrai succès des sujets de Nanoc (qui sont en C++ mais c'est dommage qu'il n'y ait pas la meme rubrique mais en C). AMHA, si les zexos veulent cibler un public de débutants, il faut absolument limiter la difficulté de ces exercices, éviter toute question d'algorithmique pure, soigner les spécifications et surveiller la précision des énoncés


--> plutôt d'accord, mais il serait bon de savoir le niveau du public qui participe !
pour ma part : débutant, 4 mois d'apprentissage du C
@+
@+

Édité le 22/12/2008 à 10:44:14 par zx-spectrum
Hors ligne candide # Posté le 22/12/2008 à 11:31:11
"In C ode we trust"
Avatar

Citation : zx-spectrum

pour ma part : débutant, 4 mois d'apprentissage du C

Ce n'est pas une information vraiment exploitable : ton niveau dépend de ton background, de ton mode d'apprentissage, de la durée quotidienne que tu y passes (moi, quand je me suis lancé dans le C, TOUT mon temps libre y passait), etc. Par exemple, tu as assimilé jusqu'à quel chapitre du cours officiel du sdz ?


 
Hors ligne zerozeroun # Posté le 22/12/2008 à 11:32:35
Usager=Inconscient+Exigeant
Avatar

Bonjour,

Je viens vous proposer un exercice.
Dans la prise en main de la SDL, je viens rajouter un exercice qui ne ferait pas une si mauvaise transition pour le TP du Sokoban: L'usage des tableau 2D.
En effet, je vous propose de créer un damier par manipulation de surfaces.
Une façon de faire ce code est d'utiliser le tableau à deux dimensions.
Mon code ressemblerait à celui des dégradés proposés par M@téo21 dans son tutoriel... (je n'en dis pas plus, je pense que c'est largement suffisant!!!)

Je vous proposerai ma solution mardi 23 Décembre!!!
Ok??? Savez-vous pour quoi? C'est parce qu'il y a mieux comme cadeau pour vous à Noël!!!

Cheers,
Zerozeroun


Le savoir est de beaucoup la portion la plus considérable du bonheur!
 
Hors ligne candide # Posté le 22/12/2008 à 12:31:43
"In C ode we trust"
Avatar

Citation : zerozeroun

Dans la prise en main de la SDL,


A mon avis, dans cette rubrique, il faut totalement exclure tout ce qui n'est pas du C standard, en particulier la SDL.


 
Hors ligne shareman # Posté le 22/12/2008 à 13:44:27
charlotte <3
Avatar

Ville : Mertzwiller
Pays : France métropolitaine

Exactement, je m'auto-cite :
Citation : premier post
aucune installation d'une bibliothèque non-standard ne sera nécessaire.

De plus, pour l'utilisation des tableaux 2D, il y a zAddition. ;)

Nouvel atelier : Codez votre propre petit préprocesseur pour langage C !
Citation : Woody Allen
Si l'au-delà existe, c'est à quelle distance du centre ville, et c'est ouvert jusqu'à quelle heure ?
 
Hors ligne L'Ombre Blanche # Posté le 22/12/2008 à 19:46:39
Hommage à Ewilan.
Avatar

Ville : Lyon
Pays : France métropolitaine

Et c'est giga beaucoup trop compliqué pour moi. :-°

Avec du temps, rien n'est impossible.

Sans rancune hein? ;) : Lien
 
Hors ligne candide # Posté le 22/12/2008 à 19:51:29
"In C ode we trust"
Avatar

Citation : L'Ombre Blanche
Et c'est giga beaucoup trop compliqué pour moi. :-°


Qu'est-ce qui est trop compliqué pour toi ? La NPI ? Où en es-tu dans ton apprentissage du C (quel chapitre dans le cours du sdz) ?


 
Hors ligne L'Ombre Blanche # Posté le 22/12/2008 à 20:27:09
Hommage à Ewilan.
Avatar

Ville : Lyon
Pays : France métropolitaine

J'ai buggé au cours de pointeurs, j'ai lu la suite, mais je ne l'ai pas assimilée faute de pratique.
Voici la raison de ma présence sur ce forum.

Avec du temps, rien n'est impossible.

Sans rancune hein? ;) : Lien
 
Hors ligne candide # Posté le 23/12/2008 à 00:44:10
"In C ode we trust"
Avatar

Citation : L'Ombre Blanche
J'ai buggé au cours de pointeurs


j'ai beaucoup souffert aussi donc je compatis ;)


 
Hors ligne Floooder # Posté le 23/12/2008 à 18:03:11

Je pense que pour les pointeurs, l'ideal c'est de vraiment les voir comme des adresses machines, personnellement ca m'a beaucoup aidé ;)
Hors ligne zx-spectrum # Posté le 28/12/2008 à 01:19:39
http://www.worldofspectrum.org
Avatar

bonjour,
Citation : L'Ombre Blanche
J'ai buggé au cours de pointeurs, j'ai lu la suite, mais je ne l'ai pas assimilée faute de pratique.
Voici la raison de ma présence sur ce forum.


-->je bugge moi même encore.....et je suis obligé de regarder mes petites fiches pour comprendre ce que je fais.
--> des exos sur ce sujet je suis preneur....

j'en profite au passage pour vous souhaiter à tous de joyeuses fêtes de fin d'année ! :)
@+
Édité le 28/12/2008 à 01:23:57 par zx-spectrum
Hors ligne shareman # Posté le 03/01/2009 à 21:23:16
charlotte <3
Avatar

Ville : Mertzwiller
Pays : France métropolitaine

La correction est en cours de rédaction. Je manque malheureusement de temps mais elle sera publiée bientôt.

Nouvel atelier : Codez votre propre petit préprocesseur pour langage C !
Citation : Woody Allen
Si l'au-delà existe, c'est à quelle distance du centre ville, et c'est ouvert jusqu'à quelle heure ?
 
Hors ligne $ViVi # Posté le 10/01/2009 à 13:30:13

Moi, c'est surtout les algorithmes qui me pose un problème :euh: :euh: . Ce serait bien qu'il soient un peu plus simple.

70% des bugs sont entre le clavier et la chaise
 
Hors ligne shareman # Posté le 11/01/2009 à 18:52:51
charlotte <3
Avatar

Ville : Mertzwiller
Pays : France métropolitaine

Correction pour zMath



Envois des résultats à réponse : 6

Voilà enfin la correction de l'exercice zMath avec un léger retard. :-° J'ai été très occupé ces temps-ci. C'est parti. ^^

Pour mener à bien cet exercice, il fallait apprendre à manipuler les piles. Pour cette correction, je vais reprendre les fonctions mises à disposition par Octal, je les trouve très biens et il y a tout juste ce qu'il nous faut.

Les inclusions



Commençons par le plus rapide : les inclusions. Réfléchissons ! Nous allons naturellement inclure stdio.h pour la saisie d'un calcul NPI et l'affichage du résultat. Ensuite, il nous faudra aussi inclure stdlib.h afin de pouvoir utiliser free et malloc, enfin, ces fonctions seront appelées dans les fonctions que je récupère du tuto d'Octal.
Code : C
1
2
#include <stdio.h>
#include <stdlib.h>


La manipulation des piles



Bien entendu, il nous faudra récupérer la structure que propose Octal qui nous servira à construire une pile :
Code : C
1
2
3
4
5
typedef struct pile
{
    int donnee;
    struct pile *precedent;
} Pile;

Ensuite, on va devoir pouvoir ajouter des éléments à la pile :
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
void pile_push(Pile **p_pile, int donnee)
{
        Pile *p_nouveau = malloc(sizeof *p_nouveau);
        if (p_nouveau != NULL)
        {
                p_nouveau->donnee = donnee;
                p_nouveau->precedent = *p_pile;
                *p_pile = p_nouveau;
        }
}

Enfin, l'opération inverse, c'est à dire le retrait d'un élément :
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int pile_pop(Pile **p_pile)
{
    int ret = -1;
    if (p_pile != NULL)
    {
        Pile *temporaire = (*p_pile)->precedent;
        ret = (*p_pile)->donnee;
        free(*p_pile), *p_pile = NULL;
        *p_pile = temporaire;
    }
    return ret;
}

On va même récupérer la fonction pour détruire une pile dans sa totalité. Elle sera très utile dans le cas où l'expression entrée par l'utilisateur de zMath est invalide ce qui pourrait entrainer une fuite de mémoire. Voici la fonction en question :
Code : C
1
2
3
4
5
void pile_clear(Pile **p_pile)
{
    while (*p_pile != NULL)
        pile_pop(p_pile);
}


La fonction zMath()



Maintenant, nous abordons la partie algorithmique. Nous allons construire la fonction qui va nous permettre d'interpréter des expressions NPI et qui va nous retourner le résultat du calcul. Commençons par le prototype : la fonction renverra un entier et prendra en paramètre un pointeur sur la chaîne à évaluer ainsi que la taille de la chaîne (strlen() n'est pas une fonction toujours efficace). On obtient ceci :
Code : C
1
int zMath(const char* calcul, size_t taille);

Passons à la déclaration des variables. Il nous faudra bien sûr un objet de type Pile, une variable itérateur pour parcourir la chaîne (que nous allons nommer i :p ) et trois autres variables qui vont nous servir lors de nos calculs et, à la fin, pour renvoyez le résultat.
Code : C
1
2
3
int i, temp1, temp2, final;
Pile* ma_pile = NULL;
i = temp1 = temp2 = final = 0;

(Prenez l'habitude d'initialiser vos variables, c'est toujours bon)
Ensuite, nous allons construire une boucle for afin d'itérer sur la chaîne à évaluer :
Code : C
1
for(; i < taille; i++){}

Le code que nous allons construire par la suite sera naturellement à placer à l'intérieur de la boucle.
Que faire maintenant ? C'est bien simple : il faut tester la nature du caractère lu à chaque tour de boucle. Six cas de figures sont possibles :
  • On a affaire à un chiffre. Dans ce cas, si vous avez bien compris le principe de la NPI, vous devriez savoir qu'il nous suffit d'ajouter ce chiffre dans la pile :
    Code : C
    1
    2
    3
    4
    if(calcul[i] >= '0' && calcul[i] <= '9') // si c'est un chiffre...
        pile_push(&ma_pile,calcul[i]-'0');
        // '-0' permet de "convertir" l'information numérique
        // d'un caractère en "vrai" chiffre
    
  • On a affaire au caractère '*' (fois). On multiplie les deux derniers éléments de la pile entres eux, tout en les retirant, et on ajoute le résultat à la pile :
    Code : C
    1
    2
    3
    4
    5
    6
    else if(calcul[i] == '*')
    { // multiplication
        temp1 = pile_pop(&ma_pile);
        temp2 = pile_pop(&ma_pile);
        pile_push(&ma_pile, temp2*temp1);
    }
    
  • Idem pour la division :
    Code : C
    1
    2
    3
    4
    5
    6
    else if(calcul[i] == '/')
    { // division
        temp1 = pile_pop(&ma_pile);
        temp2 = pile_pop(&ma_pile);
        pile_push(&ma_pile, temp2/temp1);
    }
    
  • Idem pour l'addition :
    Code : C
    1
    2
    3
    4
    5
    6
    else if(calcul[i] == '+')
    { // addition
        temp1 = pile_pop(&ma_pile);
        temp2 = pile_pop(&ma_pile);
        pile_push(&ma_pile, temp2+temp1);
    }
    
  • Et encore idem pour la soustraction :p :
    Code : C
    1
    2
    3
    4
    5
    6
    else if(calcul[i] == '-')
    { // soustraction
        temp1 = pile_pop(&ma_pile);
        temp2 = pile_pop(&ma_pile);
        pile_push(&ma_pile, temp2-temp1);
    }
    
  • L'utilisateur peut aussi avoir saisi des caractères invalides (ici, il s'agit d'un caractère n'étant pas un chiffre ni un opérateur arithmétique). Dans ce cas, on affiche un beau message d'erreur :
    Code : C
    1
    2
    else // caractère invalide
        printf(" Erreur : %c n'est pas considéré comme un caractere valide ! \n", calcul[i]);
    

Ce sera tout pour le contenu de la boucle for, vous pouvez donc la fermer ( :p :p ). Il nous reste à renvoyer le résultat. Mais pas si vite ! Il est possible, si l'utilisateur a voulu faire le malin, que la pile contient encore plus d'un élément. Il faut donc appeler la fonction pile_clear() avant de renvoyer le résultat. On obtient donc logiquement ceci :
Code : C
1
2
3
final = pile_pop(&ma_pile);
pile_clear(&ma_pile); // au cas où ...
return final;

Et voilà ! En résumé, on obtient le code complet de la fonction zMath() suivant :
Secret (cliquez pour afficher)
Code : C
 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
int zMath(const char* calcul, size_t taille)
{
    int i, temp1, temp2, final;
    Pile* ma_pile = NULL;
    i = temp1 = temp2 = final = 0;

    for(; i < taille; i++)
    {
        if(calcul[i] >= '0' && calcul[i] <= '9') // si c'est un chiffre...
            pile_push(&ma_pile,calcul[i]-'0');
        // '-0' permet de "convertir" l'information numérique d'un caractère en "vrai" chiffre
        else if(calcul[i] == '*')
        { // multiplication
            temp1 = pile_pop(&ma_pile);
            temp2 = pile_pop(&ma_pile);
            pile_push(&ma_pile, temp2*temp1);
        }
        else if(calcul[i] == '/')
        { // division
            temp1 = pile_pop(&ma_pile);
            temp2 = pile_pop(&ma_pile);
            pile_push(&ma_pile, temp2/temp1);
        }
        else if(calcul[i] == '+')
        { // addition
            temp1 = pile_pop(&ma_pile);
            temp2 = pile_pop(&ma_pile);
            pile_push(&ma_pile, temp2+temp1);
        }
        else if(calcul[i] == '-')
        { // soustraction
            temp1 = pile_pop(&ma_pile);
            temp2 = pile_pop(&ma_pile);
            pile_push(&ma_pile, temp2-temp1);
        }
        else // caractère invalide
            printf(" Erreur : %c n'est pas considéré comme un caractere valide ! \n", calcul[i]);
    }
    final = pile_pop(&ma_pile);
    pile_clear(&ma_pile); // au cas où ...
    return final;
}


On teste !



Je vous donne donc un main pour tester tout cela ;) :
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
int main(void)
{
    char saisie[200];
    int i;
    printf("Votre calcul NPI : ");
    fgets(saisie,200,stdin); // saisie

    for(i = 0; i<200; i++)
    {
        if(saisie[i] == '\n') // là où l'utilisateur a appuyé sur entrer...
        { // ...on marque juste la fin de chaîne pour pouvoir utiliser strlen
            saisie[i] = '\0';
            break;
        }
    }

    printf("Résultat : %i", zMath(saisie,strlen(saisie)));
    return 0;
}

Notez que j'utilise strlen() (oui, si l'on marque la fin de la chaîne à évaluer par '\0', strlen est fiable), incluez donc string.h si vous ne voulez pas vous retrouver avec un joli warning. ;) En compilant ce code, on peut rapidement s'apercevoir qu'il fonctionne :
Code : Console
Votre calcul NPI : 13+41+*
Résultat : 20

Bien sûr, on peut facilement améliorer tout cela, par exemple en gérant l'opérateur '^' pour les puissances, ou en vérifiant la validité de l'expression NPI.

Merci à tous les participants !

crys
Édité le 14/01/2009 à 16:15:02 par shareman

Nouvel atelier : Codez votre propre petit préprocesseur pour langage C !
Citation : Woody Allen
Si l'au-delà existe, c'est à quelle distance du centre ville, et c'est ouvert jusqu'à quelle heure ?
 
Hors ligne birdroun # Posté le 11/01/2009 à 23:23:39

Si sa c'est un "EXERCICES POUR DÉBUTANTS EN C" je croit que mon dico s'est gouré sur la definition du mot debutant ... .
Hors ligne shareman # Posté le 12/01/2009 à 00:33:37
charlotte <3
Avatar

Ville : Mertzwiller
Pays : France métropolitaine

En fait, l'exercice était plus simple que tu ne le crois. Mais, tu as raison. D'ailleur, je me suis juré de proposer des exercices plus simples et le prochain sera plus simple.

Nouvel atelier : Codez votre propre petit préprocesseur pour langage C !
Citation : Woody Allen
Si l'au-delà existe, c'est à quelle distance du centre ville, et c'est ouvert jusqu'à quelle heure ?
 
Hors ligne May_Hop # Posté le 13/01/2009 à 17:10:19
Avatar

Dommage que tu n'expliques pas comment gérer les nombres à plus d'un chiffre, mais peut-être tu as eu peur de mettre trop de notions d'algorithme.

Et sinon :
Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
else if(calcul[i] == '*')
        { // multiplication
            temp1 = pile_pop(&ma_pile);
            temp2 = pile_pop(&ma_pile);
            pile_push(&ma_pile, temp2*temp1);
        }
        else if(calcul[i] == '/')
        { // division
            temp1 = pile_pop(&ma_pile);
            temp2 = pile_pop(&ma_pile);
            pile_push(&ma_pile, temp2/temp1);
        }
        else if(calcul[i] == '+')
        { // addition
            temp1 = pile_pop(&ma_pile);
            temp2 = pile_pop(&ma_pile);
            pile_push(&ma_pile, temp2+temp1);
        }
        else if(calcul[i] == '-')
        { // soustraction
            temp1 = pile_pop(&ma_pile);
            temp2 = pile_pop(&ma_pile);
            pile_push(&ma_pile, temp2-temp1);
        }


C'est moche et redondant ! La preuve, tu as même fait du copier/coller (cf commentaires).
Mieux vaut faire une fonction spécifique pour ceci et surtout mettre :
Code : C
1
2
temp1 = pile_pop(&ma_pile);
            temp2 = pile_pop(&ma_pile);

seulement une fois en début de fonction et pas tout le long du code ...

Tu peux aussi utiliser un switch qui est, je pense, plus approprié ici (après c'est aussi question de goût).

Code : C
 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
void calcul(Pile **pile, char operateur)
{
    int val1 = 0, val2 = 0;
    val1 = depiler(pile);
    val2 = depiler(pile);

    switch(operateur)
        {
            case '+' :
                empiler(pile, val1+val2);
                break;
            case '-' :
                empiler(pile, val2-val1);
                break;
            case '/' :
                empiler(pile, val2/val1);
                break;
            case '*' :
                empiler(pile, val1*val2);
                break;
            default :
                printf("ERREUR : Mauvaise entree\n");
                break;
        }
}


Hors ligne shareman # Posté le 13/01/2009 à 19:29:42
charlotte <3
Avatar

Ville : Mertzwiller
Pays : France métropolitaine

J'ai horreur des switch. ;) Pour l'idée de la factorisation du code, tu n'es pas sûr de tomber sur un opérateur, la solution serait alors de créer une deuxième fonction - comme tu l'as fait -, ce qui impliquerait au moins un test non-nécessaire. Je préfère ma méthode et entres-nous, je pense qu'ici, ce détail de répétition est largement négligeable (je ne suis pas un puriste du C). ;) Et sinon, non, je n'ai rien copié-collé.

Citation : May_Hop
Dommage que tu n'expliques pas comment gérer les nombres à plus d'un chiffre, mais peut-être tu as eu peur de mettre trop de notions d'algorithme.

Tout à fait. Déjà qu'on m'en veut de proposer des exercices comme celui-là. ^^ Pour gérer les nombres à plus d'un chiffre, je pense que le mieux est de commencer par lexer la chaîne avant traitement.
Édité le 13/01/2009 à 19:35:54 par shareman

Nouvel atelier : Codez votre propre petit préprocesseur pour langage C !
Citation : Woody Allen
Si l'au-delà existe, c'est à quelle distance du centre ville, et c'est ouvert jusqu'à quelle heure ?
 
Hors ligne May_Hop # Posté le 13/01/2009 à 19:43:49
Avatar

Citation : crys'
Et sinon, non, je n'ai rien copié-collé.



Citation : crys'
Code : C
1
2
3
4
5
6
else if(calcul[i] == '*')
{ // multiplication
    temp1 = pile_pop(&ma_pile);
    temp2 = pile_pop(&ma_pile);
    pile_push(&ma_pile, temp2*temp1);
}

Idem pour la division :
Code : C
1
2
3
4
5
6
else if(calcul[i] == '/')
{ // multiplication
    temp1 = pile_pop(&ma_pile);
    temp2 = pile_pop(&ma_pile);
    pile_push(&ma_pile, temp2/temp1);
}



A moins que tu es tapé 4 fois de suite de le commentaire multiplication ...

Citation : crys'
tu n'es pas sûr de tomber sur un opérateur


Le default est là pour ça. A moins que tu parles d'autres choses.
Code : C
1
2
3
default :
                printf("ERREUR : Mauvaise entree\n");
                break;


Suffit de faire quelque chose dans le genre :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
int zMath(const char* calcul, size_t taille)
{
    int i, temp1, temp2, final;
    Pile* ma_pile = NULL;
    i = temp1 = temp2 = final = 0;

    for(; i < taille; i++)
    {
        if(calcul[i] >= '0' && calcul[i] <= '9') // si c'est un chiffre...
            pile_push(&ma_pile,calcul[i]-'0');
        // '-0' permet de "convertir" l'information numérique d'un caractère en "vrai" chiffre
        else 
            calcul(blablabla);

    final = pile_pop(&ma_pile);
    pile_clear(&ma_pile); // au cas où ...
    return final;
}
Hors ligne shareman # Posté le 13/01/2009 à 19:49:01
charlotte <3
Avatar

Ville : Mertzwiller
Pays : France métropolitaine

D'accord, mais alors dans le default, il faut rempiler ce que tu as dépilé au début. Moi, je préfère dépiler uniquement quand c'est nécessaire.
Citation : May_Hop
A moins que tu es tapé 4 fois de suite de le commentaire multiplication ...

Bien sûr que non. Quand je disais "je n'ai rien copié-collé", je parlais du copier-coller durant la rédaction du post. Or ce n'est pas le cas, c'est une inattention qui était déjà présente dans le main.c de mon code, à la base donc. J'édite et puis de toute façon, ça n'a pas grande importance.

Je posterai le prochain exercice demain, et, je vous le promet, il sera simple ! ^^
Édité le 13/01/2009 à 19:53:18 par shareman

Nouvel atelier : Codez votre propre petit préprocesseur pour langage C !
Citation : Woody Allen
Si l'au-delà existe, c'est à quelle distance du centre ville, et c'est ouvert jusqu'à quelle heure ?
 
Hors ligne May_Hop # Posté le 13/01/2009 à 21:06:32
Avatar

Citation : crys'
D'accord, mais alors dans le default, il faut rempiler ce que tu as dépilé au début. Moi, je préfère dépiler uniquement quand c'est nécessaire.


Ah oui. Mais bon en même temps il suffit de rajouter une seule condition. La lisibilité du code serait largement mieux !


Quand tu fais un copier/coller dans un code, car c'est l'origine de cette répétition (sauf si erreur ;) ), il faut se poser des questions et voir si on ne peut pas éviter ces répétitions.

Retour au forum "Langage C" ou à la liste des forums

Pour accéder à cette section
Connectez-vous !
connexion_rpx