Erreur dans le programme...

Fermé
Kyky - 9 févr. 2016 à 18:27
 Kyky - 11 févr. 2016 à 19:56
Bonjour,
je ne trouve pas l'erreur, le programme me demande les notes et dès que j'ai fini de les saisir, il cesse de fonctionner... Pouvez-vous m'aider?

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void) {
    char NoteUn[5], NoteDeux[5], NoteTrois[5], NoteQuatre[5], NoteCinq[5], NoteSix[5];                     //Crée des variables pour les notes
    char CoeffUn[4], CoeffDeux[4], CoeffTrois[4], CoeffQuatre[4], CoeffCinq[4], CoeffSix[4];               //Crée des variables pour les coefficients respectifs de chaque note
    char Moyenne;

    printf("***** Programme de calcul d'une moyenne ponderee *****\n\n");

    printf("Entrez la premiere note:");
    fgets(NoteUn, sizeof(NoteUn), stdin);
    printf("Voici la note saisie: %s", NoteUn);
    printf("Quel est son coefficient? :");
    fgets(CoeffUn, sizeof(CoeffUn), stdin);

    printf("\nEntrez la deuxieme note:");
    fgets(NoteDeux, sizeof(NoteDeux), stdin);
    printf("Voici la note saisie: %s", NoteDeux);
    printf("Quel est son coefficient? :");
    fgets(CoeffDeux, sizeof(CoeffDeux), stdin);

    printf("\nEntrez la troisieme note:");
    fgets(NoteTrois, sizeof(NoteTrois), stdin);
    printf("Voici la note saisie: %s", NoteTrois);
    printf("Quel est son coefficient? :");
    fgets(CoeffTrois, sizeof(CoeffTrois), stdin);

    printf("\nEntrez la quatrieme note:");
    fgets(NoteQuatre, sizeof(NoteQuatre), stdin);
    printf("Voici la note saisie: %s", NoteQuatre);
    printf("Quel est son coefficient? :");
    fgets(CoeffQuatre, sizeof(CoeffQuatre), stdin);

    printf("\nEntrez la cinquieme note:");
    fgets(NoteCinq, sizeof(NoteCinq), stdin);
    printf("Voici la note saisie: %s", NoteCinq);
    printf("Quel est son coefficient? :");
    fgets(CoeffCinq, sizeof(CoeffCinq), stdin);

    printf("\nEntrez la sixieme note:");
    fgets(NoteSix, sizeof(NoteSix), stdin);
    printf("Voici la note saisie: %s", NoteSix);
    printf("Quel est son coefficient? :");
    fgets(CoeffSix, sizeof(CoeffSix), stdin);

    Moyenne = ((char)NoteUn * (char)CoeffUn + (char)NoteDeux * (char)CoeffDeux + (char)NoteTrois * (char)CoeffTrois + (char)NoteQuatre * (char)CoeffQuatre + (char)NoteCinq * (char)CoeffCinq + (char)NoteSix * (char)CoeffSix) / ((char)CoeffUn + (char)CoeffDeux + (char)CoeffTrois + (char)CoeffQuatre + (char)CoeffCinq + (char)CoeffSix) ;
    printf("La moyenne est de : %s", Moyenne);

    return 0;
}

3 réponses

Bonsoir.

Pourquoi le type de vos variables est "char" ? Les notes, c'est des nombres non ?
Comment pouvez-vous effectuer des operations entre des caracteres ?

EchoIsON.
0
Bonsoir!

Pourquoi le type de vos variables est "char" ? Les notes, c'est des nombres non ?

Donc le problème viendrait des types : il faudrait des "unsigned char" par exemple, c'est cela? Ou des "unsigned float", si l'on veut des nombres à virgule?

Comment pouvez-vous effectuer des operations entre des caracteres ?

Pour ceci, je ne sais pas du tout comment faire... Je sais qu'il faut peut-être utiliser des "%s" ou quelque chose comme ceci, mais je n'ai pas vraiment compris comment les utiliser...

Merci de m'avoir répondu si tôt,
Kyky
0
Bonsoir.

Nous sommes-nous mal compris ?

On veut bien des nombres.
char est une variable pour stocker un caractère, comme 'A', 'B', 'X' etc.
Par exemple :
int est une variable pour stocker un nombre entier (42, 152, 47, 0...)
double est une variable pour stocker un nombre à virgule (42,42; 58,54; 1,0249...)
Le fait d'ajouter unsigned devant une variable de type nombre permet de stocker des nombres positifs ou nuls, non négatifs, c'est tout.

Certes, char permet de stocker certains nombres (très peu), mais cette variable n'est pas faite pour cela, on stocke les nombres dans int, double ou float par exemple.
char sert avant tout à stocker UNE lettre, dont le code ASCII correspond à un nombre (qui vont en l'occurence jusqu'à 127, limite de stockage du type char, coincidence ?).
Et je ne vois pas pourquoi créer des tableaux, vous pouvez faire plus simple.

Ou alors j'ai mal compris ce que vous vouliez faire...

PS : Pour répondre à votre question
Ou des "unsigned float" ?
Oui, ce serait mieux, même qu'avec des char, une moyenne négative n'étant pas possible dans ce cas. De plus, unsigned char va de 0 à 255 et non de -127 à 127.

EchoIsON.
0
jackdada Messages postés 76 Date d'inscription vendredi 31 juillet 2015 Statut Membre Dernière intervention 10 février 2016 19 > Utilisateur anonyme
Modifié par jackdada le 10/02/2016 à 01:37
char sert avant tout à stocker UNE lettre, dont le code ASCII correspond à un nombre Char sert à stocker un caractère. Ce caractère pet être une lettre, mais aussi un chiffre, ou encore des chose comme '\n', '\0'...

Et je ne vois pas pourquoi créer des tableaux, vous pouvez faire plus simple.
Il crée des tableau car il utilise un fgets et non un scanf pour les saisie, sauf qu'après, il ne convertie pas ces chaines de caractère en des nombres (entier ou flottant) c'est ce qui pose le problème justement lors du calcule de la moyenne. Mais en réalité 1 seul tableau réutilisé pour chaque saisie est nécessaire. Une autre solution est l'utilisation du scanf (à condition de le sécuriser)
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 835
10 févr. 2016 à 14:10
EchoIsOn, jackdata,
Attention aux raccourcis... Un char ne sert pas stocker une lettre, ni un caractère mais un nombre... Souvent on s'en sert pour y stocker la valeur correspondante à un caractère (code ASCII).
On peut donc tout à fait y stocker une note (une note est rarement supérieure à 255 (unsigned)). Mais si on veut un flottant, il faudra plutôt partir sur double.

Techniquement '\n' et '\0' ne sont pas des char mais des int ;-). Même si cela tient bien évidemment dans un char.
0
jackdada Messages postés 76 Date d'inscription vendredi 31 juillet 2015 Statut Membre Dernière intervention 10 février 2016 19
10 févr. 2016 à 01:30
Alors comme cela a été dit, il y a un problème sur le type de tes variable utilisé, enfin oui et non à la fois (je vais m'expliquer).
Il y a différent type de variable, qui te permettent de manipulé des caractère, des entier ou des flottant signé ou non. Je te laisse regarder ici pour plus de détaille https://forums.commentcamarche.net/forum/affich-37622105-langage-c-les-types-de-donnees

Tu souhaite manipuler des nombres, char n'est donc pas le type approprié. Il faut donc utilisé des int ou des float. Ce sont des notes, elles peuvent être à virgule, on partira donc sur des float.

Pour la saisie de tes nombre, tu as choisit d'utiliser fgets sauf que ceci crée des chaines de caractère et non des nombres. Il faut donc après avoir saisie un nombre sous forme de chaine de caractère avec fgets, le transformer en float avec strtof().
char entree[5];
float nombre;
fgets(entree, sizeof(entree), stdin);
nombre = strtof(entree, NULL);

Il faut donc maintenant changer tes définition de variable par le type approprié et en rajouté une qui sera la chaine de caractère utilisé pour la saisie.
char entree[5]; //Crée un tableau de 5 caractère pour stocker la chaine de caractère d'entrée.
float NoteUn, NoteDeux, NoteTrois, NoteQuatre, NoteCinq, NoteSix; //Crée des variables pour les notes
float CoeffUn, CoeffDeux, CoeffTrois, CoeffQuatre, CoeffCinq, CoeffSix; //Crée des variables pour les coefficients respectifs de chaque note
float Moyenne; //Crée une variable pour la moyenne

Après chaque fgets(entree, sizeof(entree), stdin), tu devra rajouter la conversion d'une chaine en un flottant. Vider le buffer après une saisie est également plus propre.

Exemple pour la saisie de NoteUn et CoefUn:
char c;
printf("Entrez la premiere note:");
fgets(entree, sizeof(entree), stdin);
while ((c = getchar()) != '\n' && c != EOF) ;//on vide le buffer
NoteUn = strtof(entree, NULL);
printf("Voici la note saisie: %s", NoteUn);
printf("Quel est son coefficient? :");
fgets(entree, sizeof(entree), stdin);
while ((c = getchar()) != '\n' && c != EOF) ;//on vide le buffer
CoeffUn = strtof(entree, NULL);

Il faudra aussi que tu enlève les (char) dans le calcule de la moyenne.


Une autre solution est également possible, si tu ne souhaite pas t’embêter avec la conversion de chaine de caractère en flottant.
L'utilisation du bon vieux scanf:
float nombre;
char c;
int r;
do
{
printf("Entrez un nombre\n");
r=scanf("%f", &nombre);
while ((c = getchar()) != '\n' && c != EOF) ;//on vide le buffer
}while(r!=1); //j'utilise mon scanf dans une boucle afin de la sécurisé. Ainsi si ma saisie n'est pas autorisée (un caractère au lieu d'un chiffre par exemple), alors je boucle et redemande la saisie.


Je te met si après, le code que j'aurais fait pour le calcule de la moyenne en plus optimisé (fait avec des scanf, mais il est facilement transposable avec des fgets):
#include <stdio.h>
#include <stdlib.h>

int main(){
   
   int i;
   int r;
   char c;
   int nbNote;
   float sumNote=0;
   float sumCoeff=0;
   float moyenne;
   

   do{
      printf("Nombre de note?\n");
      r=scanf("%d", &nbNote);
      while ((c = getchar()) != '\n' && c != EOF) ;
   }while(r!=1);
   float noteTab[nbNote][nbNote];
   
   for(i=0; i<nbNote; i++){
      do{
         printf("Note %d?\n", i);
         r=scanf("%f", ¬eTab[i][0]);
         while ((c = getchar()) != '\n' && c != EOF) ;
      }while(r!=1);
      do{
         printf("Coeff de la note %d?\n", i);
         r=scanf("%f", ¬eTab[i][1]);
         while ((c = getchar()) != '\n' && c != EOF) ;
      }while(r!=1);
      printf("La note %d est %.2f de coeff %.2f\n", i, noteTab[i][0], noteTab[i][1]);
      sumNote+= noteTab[i][0] * noteTab[i][1];
      sumCoeff+= noteTab[i][1];
   }
   moyenne = sumNote/sumCoeff;
   printf("Moyenne: %.2f\n", moyenne);
   return 0;
}
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié par [Dal] le 10/02/2016 à 11:39
Salut jackdada,

Je n'ai pas tout lu, mais à propos de ton dernier code, voilà quelques observations.

pour des nombres décimaux, sauf besoin particulier, utiliser des double est plus cohérent, et ton main devrait avoit un prototype
int main(void)
.

si on ne fait qu'additionner des notes pondérées avec des coefficients et additionner des coefficients, on calcule au fur et à mesure et le stockage dans un tableau n'est pas nécessaire, car il n'y a pas réutilisation des données.

ton tableau
float noteTab[nbNote][nbNote];
nécessite C99.

outre le fait que le stockage n'est pas indispensable, le tableau utilise un espace inutile, puisque tu as juste besoin de 2 colonnes : une pour stocker la note, l'autre pour stocker le coefficient. Il ne faut pas autant de colonnes que de lignes.

les scanf pourraient, pour chaque note, demander la note et le coefficient, séparés par un espace. cela réduirait la redondance du code.


Dal
0
jackdada Messages postés 76 Date d'inscription vendredi 31 juillet 2015 Statut Membre Dernière intervention 10 février 2016 19 > [Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024
10 févr. 2016 à 15:45
Le retour de la fameuse question du pourquoi float et pourquoi double. Je n'ai jamais bien saisie la différence entre ces deux type de flottant, hormis le fait que la taille du double est supérieur à celle du float, que lorsque l'on utilise un nombre à virgule dans une opération (3.5+2.6) ce sont en faite des double et qu'un nombre à virgule, 3.5 par exemple est différent s'il est dans un float ou dans un double.

Du fait qu'on manipule des note (qui ne sont donc pas volumineuse), pourquoi partir sur un double plutôt qu'un float. La logique voudrait d'utiliser un float du fait qu'il prend moins de place en mémoire non? Car moins de place en mémoire utilisé impliquerait moins de calcul donc un cout plus faible et une meilleurs optimisation. Pour m'a part ça a toujours été un peut au feeling entre float et double (tout dépend de la taille des donné qui seront utilisé), comme la personne du topic que tu ma passer. Et je ne trouve jamais de réponse précise à ce propos, a part en générale on utilisera un double.

Pour le tableau je suis repartit sur le fait qu'il stockait chaque note, mais vue que je fait le calcule au fur et a mesure avec sumNote et sumCoeff, c'est vrais que c'est inutile. Et pour sa taille je ne sais pas pourquoi je suis partit sur autant de ligne que de colonne sachant que je n'en utilise que 2 (surement la fatigue deriere cette histoire), la taille adéquate serait float noteTab[nbNote][2];
Pour ce qui est du c99, ceci à une importance uniquement pour le compilateur et comment il est configuré. Ce dernier lui signalera en cas de besoins du flag std=c99. Utilisant gcc, il y ai par défaut.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 835
10 févr. 2016 à 16:00
Le traitement d'un double n'est pas forcément plus long qu'un float. Cela dépend de pas mal de paramètre (compilateur / processeur, ...). Bref, la règle est simple : on utilise toujours double, sauf lorsque la place est critique :-).

Pour le C99, ce que voulait dire [Dal], c'est que l'instruction que tu as donnée n'est pas correcte en C89/90. Il vaut donc mieux plutôt utiliser les malloc... D'autant que pour un exercice scolaire, ça risque d'être considéré comme faux le VLA...
0
jackdada Messages postés 76 Date d'inscription vendredi 31 juillet 2015 Statut Membre Dernière intervention 10 février 2016 19
10 févr. 2016 à 21:22
La norme c99 n'a pas été inventé pour rien, pourquoi ne pas tirer profit des évolution apporté à un langage. J'ai moi même appris en école à utiliser le VLA donc c'est tout à fait correct de le faire sur un exercice scolaire.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 835
10 févr. 2016 à 23:08
donc c'est tout à fait correct de le faire sur un exercice scolaire.
Sauf que c'est son prof qui choisit ;-). Et vu le niveau de l'exercice, il y a de fortes chances qu'il en soit à son début et qu'il ne connaisse pas encore le VLA. Même pas sûr qu'il connaisse l'allocation dynamique avec malloc()...
En tout cas, sur ce forum, c'est la 1ère fois que j'entends que le VLA est toléré à l'école.
Après, kyky est grand et prendra le risque s'il est joueur.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 835
10 févr. 2016 à 13:52
Salut jackdata,

Je rajoute quelques par rapport aux remarques de [Dal].

fgets(entree, sizeof(entree), stdin);
while ((c = getchar()) != '\n' && c != EOF) ;//on vide le buffer

c n'est pas un char, mais un int.
Attention, tu ne peux pas vider le buffer comme ça puisque fgets() stocke le '\n' s'il y a la place.
Il faut t'assurer que le buffer clavier contient bien des données...


0
jackdada Messages postés 76 Date d'inscription vendredi 31 juillet 2015 Statut Membre Dernière intervention 10 février 2016 19
Modifié par jackdada le 10/02/2016 à 15:46
Effectivement, j'ai oublier de prendre ça en compte, le '\n' qui peut être stocker par fgets (n'utilisant jamais fgets, mais uniquement des scanf, j'ai pas l'habitude de faire cette vérification)
Il faut faire appel à cette fonction du coup pour vider le buffer(si besoins) suite au fgets (je l'ai mit dans une fonction cette fois car ça prend quelque ligne):
void clean(char *chaine){
   int c;
   char *p = strchr(chaine, '\n');
   if(p)
      *p = 0;
   else
      while ((c = getchar()) != '\n' && c != EOF) ;
}

Donc après le fgets(entree, sizeof(entree), stdin); , il faut faire appel à la fonction par cette ligne clean(entree);


D'ailleurs une petite question pour toi fiddy, que ce produit il quand on utilise directement while ((c = getchar()) != '\n' && c != EOF) ; sans faire la vérification sur le '\n'
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 835
Modifié par fiddy le 10/02/2016 à 15:44
Il manque juste l'accolade et c'est parfait :-). De plus, avant d'appeler cette fonction, il vaudra mieux vérifier que fgets() a renvoyé une valeur non NULL.
Pour répondre à ta question, si tu oublies cette vérification et qu'il n'y a pas de '\n' dans le buffer, cela attendra tout simplement que l'utilisateur saisisse une donnée au clavier (avec validation). Mais sans affichage, l'utilisateur risque de penser que le programme a planté...
0
jackdada Messages postés 76 Date d'inscription vendredi 31 juillet 2015 Statut Membre Dernière intervention 10 février 2016 19 > fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022
10 févr. 2016 à 15:47
J'ai rajouté l’accolade de fermeture oublié, merci de ta réponse
0