Je ne peux scanf une chaine

Résolu/Fermé
T-Monde99 - 10 oct. 2022 à 06:06
 Tmmonde99 - 11 oct. 2022 à 05:59

le topping esgt une chaine je ne peux le scanf du coup mon code ne marche pas dutout. En plus j'aimerais dfaire en sorte que si on n;'ajoute pas "$" avant le montant le systeme redemande d'entrer le montant ou crache. 

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

int main()
{
char topping[24];
int slices;
int month, day, year;
float cost;
printf("Combien coute une pizza dans votre region?\n");
printf("Entrer une somme en n'oubliant pas de mettre le signe $ avant le montant : \n");
scanf("%f",&cost);

printf("\n Quelle est votre garniture de pizza preferee en un mot? :\n");
scanf(" %s", &topping[24]);

printf("Combien de tranches de pizzas %s",topping);
printf("pouvez vous manger en une seule fois? :\n");
scanf("%d", &slices);

printf("Quelle est la date d'aujourd'hui? (Entrer le au format JJ/MM/AAA)\n");
scanf("%d%d%d",day,month,year);

printf("\n\n Pourquoi ne pas vous offrir un diner le %d%d%d",month,day,year);
printf("\n et prendre %d slices of %s pizzas! \n",slices,topping);
printf("Cela ne vous coutera que $%2f!\n\n\n", cost);
    return 0;
}

3 réponses

jordane45 Messages postés 38241 Date d'inscription mercredi 22 octobre 2003 Statut Modérateur Dernière intervention 17 septembre 2024 4 689
10 oct. 2022 à 06:32

Bonjour

scanf(" %s", &topping);

Pour ta seconde question, interresse toi à la boucle while..


0

Merci. Mais c'est ce que j'ai dans mon code. Quand je compile ça. On saute lq question quelle est votre garniture préférée. On va directement à combien de tranches. 

0
Whismeril Messages postés 19145 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 29 septembre 2024 919
10 oct. 2022 à 07:31

Bonjour

la question et son scanf avant "la garniture" est

printf("Entrer une somme en n'oubliant pas de mettre le signe $ avant le montant : \n");
scanf("%f",&cost);

Or, $ n'est pas un nombre, à mon avis, tu devrais lire cette autre discussion :

https://forums.commentcamarche.net/forum/affich-37704224-fonction-scanf-pas-lue-par-le-programme-langage-c


0
[Dal] Messages postés 6193 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 4 juillet 2024 1 090
10 oct. 2022 à 10:17

Bonjour T-Monde99,

jordane45 a raison pour ta ligne 15 qui devrait contenir quelque chose comme

scanf("%s", &topping); 

pour lire un seul mot, en ignorant les caractères "blancs" (espace, tabulation, retour à la ligne) éventuels qui le précèdent (l'espace proposé par Jordane n'est pas nécessaire ici, car %s consomme déjà les caractères "blancs"), et mettre le résultat de la lecture à l'adresse de la première case du tableau topping. Ton code mettait le résultat à partir de la 25ème case, ce qui est erroné (et, de plus, va au-delà de la mémoire attribuée au tableau).

Whismeril te dit très exactement que ton spécificateur en ligne 12 

scanf("%f",&cost);

est pour la lecture d'un float et pas d'un $ suivi d'un nombre décimal.

Pour lire "$15.50"  sans rien avant le signe $ ni rien entre le signe $ et le nombre, le spécificateur serait :

scanf("$%f",&cost);

Si tu veux que le scanf() réussisse à lire le nombre même si l'utilisateur met un ou plusieurs espaces avant ou après le signe $, par exemple, il tape "   $  15.50", tu peux écrire :

scanf(" $ %f",&cost);

Maintenant que se passe-t-il si l'utilisateur ne respecte pas le format demandé et oublie de taper le $ devant la somme ?

  • le buffer du flux stdin va contenir, par exemple "15,50" et Entrée
  • scanf() va échouer à lire le le buffer du flux stdin, car dès le premier char il ne correspond pas au format demandé,
  • scanf() va donc retourner 0 (la valeur de retour de scanf() indique, en effet, le nombre d'éléments lus, ce qui est un moyen de vérifier si scanf() a réussi, ou pas, à faire ce qu'on lui demandait)
  • la variable cost ne sera pas initialisée avec quoi que ce soit et contiendra n'importe quoi
  • l'exécution du programme va passer à la ligne suivante
  • lorsqu'on arrive au prochain scanf() ce 2ème appel n'interrompt pas l'exécution du programme, car il y a toujours "15,50" dans le buffer du flux stdin
  • ce 2ème scanf() qui attend une chaîne "%s" consomme ce contenu en tant que chaîne et s'arrête au premier caractère blanc suivant (Entrée est un caractère "blanc")

Ce qu'il faut retenir :

  • scanf() travaille sur le buffer du flux stdin en consommant son contenu s'il correspond aux spécificateurs de format
  • scanf() retourne le nombre d'éléments lus, ce qui permet de vérifier sa bonne exécution, et de réagir si ce n'est pas le cas
  • scanf() laisse dans le buffer du flux stdin tout ce qui ne correspond pas aux spécificateurs du format
  • si on veut vider le buffer du flux stdin, il faut consommer tout ce qui y reste

Dans la discussion récente dont Whismeril donne le lien, au sujet d ece dernier point, j'indique ceci :

Pour être sûr que le tampon de stdin est vide, après chaque scanf() on peut faire ceci :

    int c;
    while((c = getchar()) != '\n' && c != EOF)
        /* on consomme tout ce qui reste dans stdin */ ;

On peut mettre ces lignes telles quelles dans une fonction empty_stdin() et l'appeler après chaque appel à scanf().

scanf() est l'une des fonctions les plus complexes de la bibliothèque standard du langage C.


0
[Dal] Messages postés 6193 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 4 juillet 2024 1 090
10 oct. 2022 à 10:29

Il y a d'autres erreurs dans ton code, mais maintenant tu devrais savoir comment les corriger.

Note aussi qu'en compilant ton code avec les Warnings, gcc signale aussi ceci :

37704443.c: In function ‘main’:
37704443.c:22:9: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int’ [-Wformat=]
 scanf("%d%d%d",day,month,year);
        ~^      ~~~
37704443.c:22:11: warning: format ‘%d’ expects argument of type ‘int *’, but argument 3 has type ‘int’ [-Wformat=]
 scanf("%d%d%d",day,month,year);
          ~^        ~~~~~
37704443.c:22:13: warning: format ‘%d’ expects argument of type ‘int *’, but argument 4 has type ‘int’ [-Wformat=]
 scanf("%d%d%d",day,month,year);
            ~^            ~~~~
37704443.c:22:1: warning: ‘day’ is used uninitialized in this function [-Wuninitialized]
 scanf("%d%d%d",day,month,year);
 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
37704443.c:22:1: warning: ‘month’ is used uninitialized in this function [-Wuninitialized]
37704443.c:22:1: warning: ‘year’ is used uninitialized in this function [-Wuninitialized]
0

D'accord merci. Maintenant j'ai utilisé la fonction empty. Mais le programme se crache après  avoir demander d'entrer la date d'aujourd'hui et du coup ne prend ps en compte le dernier bloc d'instruction. 

0
[Dal] Messages postés 6193 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 4 juillet 2024 1 090 > Tmmonde99
Modifié le 10 oct. 2022 à 17:17

Peux-tu poster ton nouveau code ?

Lorsque tu postes ton code sur le forum, fais le en cliquant sur le bouton "Insérer un extrait de code" du forum (à droite du bouton image) et en choisissant le langage C/C++ afin qu'il soit correctement affiché.

Tu ne précises pas si tu as corrigé les problèmes signalés par les warnings rappelés ci-dessus. Si tu ne l'as pas fait, cela peut expliquer ton plantage.

0
T-Monde99 > [Dal] Messages postés 6193 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 4 juillet 2024
10 oct. 2022 à 17:25
#include <stdio.h>
#include <stdlib.h>

int main()
{
char topping[24];
int slices;
int month, day, year;
float cost;
printf("Combien coute une pizza dans votre region?\n");
printf("Entrer une somme en n'oubliant pas de mettre le signe $ avant le montant :");
scanf(" $ %f",&cost);

int c;
while((c = getchar()) != '\n' && c != EOF);

printf(" Quelle est votre garniture de pizza preferee en un mot? : ");
scanf("%s", &topping);

c;

printf("Combien de tranches de pizzas %s",topping);
printf("  pouvez vous manger en une seule fois? : ");
scanf("%d", &slices);

c;

printf("Quelle est la date d'aujourd'hui? (Entrer le au format JJ/MM/AAA) : ");
scanf("%d%d%d",day,month,year);
 c;

printf("\n\n Pourquoi ne pas vous offrir un diner le %d%d%d",month,day,year);
printf("\n et prendre %d slices of %s pizzas! \n",slices,topping);
printf("Cela ne vous coutera que $%2f!\n\n\n", cost);
    return 0;
}
0
[Dal] Messages postés 6193 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 4 juillet 2024 1 090 > T-Monde99
Modifié le 10 oct. 2022 à 18:25

1.

Il y a une erreur dans mon précédent post ( et plus haut dans celui de jordane45) qui est sans incidence sur ce que tu constates, mais cause un warning : il faut mieux écrire scanf("%s", topping); au lieu de scanf("%s", &topping); pour éviter ce warning.

La raison pour laquelle on n'a pas besoin de mettre l'opérateur unaire & devant le nom du tableau est que lorsque l'on passe le nom d'un tableau en paramètre d'une fonction, le C passe en réalité l'adresse mémoire du premier élément de ce tableau. Le & est donc redondant dans ce cas.

2.

Les lignes où tu écris c; tout seul sur une ligne n'ont aucun effet et ne font pas ce que tu penses. Je suggérais de créer une fonction appelant les 2 lignes de code que tu peux appeler après chaque appel à scanf().

Tu crées donc la fonction suivante avant ton main()

void empty_stdin(void) {
        int c;
        while((c = getchar()) != '\n' && c != EOF);
}

et, dans ton main(), et après chaque appel à scanf() tu peux désormais appeler cette fonction en écrivant : empty_stdin();

3.

Tu n'as effectivement pas corrigé les warnings signalés concernant le scanf() appelé pour la date dans le contexte suivant :

int month, day, year;
(...)
printf("Quelle est la date d'aujourd'hui? (Entrer le au format JJ/MM/AAA) : ");
scanf("%d%d%d",day,month,year);

Tout d'abord, tu observeras que tu n'as rien fait dans la chaîne décrivant la spécification de format pour que scanf() prenne en compte le fait que les entiers doivent être séparés par des slashs... C'est un peu dommage, car tu refais exactement la même erreur qu'avec le $ alors que tu dois savoir maintenant quoi faire.

Sinon, le crash est provoqué par ce que te disent les warnings :

warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int’ [-Wformat=]
 scanf("%d%d%d",day,month,year);

(ce warning concerne day, et il y en a 2 autres pour month et pour year)

Que te disent ces warnings ?

  • le format %d utilisé comme spécificateur de scanf() nécessite, pour obtenir un entier, que tu passes un pointeur vers cet entier, afin que scanf() dispose de l'adresse mémoire où stocker ce que scanf() aura récupéré
  • or tu lui passes un int

Comprends-tu ton erreur ?

Le warning est un avertissement généré par le compilateur à condition que tu lui passes les bonnes options de compilation.

Avec gcc, les options -Wall et -Wextra par exemple sont des options de compilation communes.

Compiles-tu avec les warnings activés ?

Lorsqu'un warning se manifeste, cela ne bloque pas la compilation (contrairement à une erreur de syntaxe), alors, si un exécutable est produit, tu peux avoir l'impression que tout c'est bien passé.

En réalité, en C, le fait que ton code compile ne signifie pas qu'il soit bon, comme tu peux le constater.

Si ton code compile avec des avertissements, c'est dans 90% des cas une erreur que tu devrais comprendre et corriger.

Le compilateur veux t'aider à débusquer ces erreurs en te signalant ces avertissements. Il faut écouter ce qu'il a à dire :-)

0