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 :

Le vilain scanf


Sujet :

C

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Deficient visuel
    Inscrit en
    Mai 2019
    Messages
    196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Deficient visuel

    Informations forums :
    Inscription : Mai 2019
    Messages : 196
    Points : 37
    Points
    37
    Par défaut Le vilain scanf
    Bonjour a toutes et a tous ,
    Puisque le scanf n'est pas conseillé , je cherche a le remplacer par une fonction plus sécurisé , du genre fgets ou autre chose . Pouvez vous m'apporter votre aide ?

    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
    121
    #include <stdio.h>
    #define prixCle 10
    #define prixOrdi 500
    float calcul(int nArticle,float prix);
     
    int main(void)
    {
     char tab[3];
     float remiseIm,remise,prix,result,paiement,billet500;
     int nArticle,choix,billet100,billet50,billet10,pieces2,pieces1,
    rendu;
     choix=0;prix=0;remise=0;remiseIm=0;nArticle=0;paiement=0; result=0;rendu=0;billet100=0;billet50=0;billet10=0;pieces2=0;
     pieces1=0;
     puts("***************************************************\n");
    puts("********** |BIENVENUE CHEZ OIM| *******************\n");
    puts("***************************************************\n");
     
     puts("Article disponible en stock:\n");
     
     puts("\tCHOIX 1:cle usb");
     puts("\t(prix a l'unité: 10 euros)\n");
     
     puts("\tCHOIX 2:ordinateur portable(10%% remise supplementaire)");
     puts("\t(prix a l'unité: 500 euros)\n");
     
     puts("\t10 article acheté,5%% de remise sur tous les articles");
     puts("\t50 article acheté,10%% de remise sur tous les articles\n");
     
     printf("Quel est votre choix?\n");
     scanf("%d",&choix);
     while((choix!=1)&&(choix!=2))
       {
        printf("Mauvais choix,recommencez\n");
        scanf("%d",&choix);
       }
     do
       {printf("Combien d'article désirez vous?\n"); 
        scanf("%d",&nArticle); 
       }while(nArticle<1);
     
     switch(choix)
     {
      case 1:
          result=calcul(nArticle,prixCle);
          printf("Vous avez choisis %d cle usb\n",nArticle);
          printf("Votre montant total sera de:%4.0f Euros\n",result);
          break; 
      case 2:
     
          result=calcul(nArticle,prixOrdi);
          printf("Vous avez choisis %d ordinateurs portable\n",nArticle);
          printf("Votre montant total sera de:%5.0f Euros\n",result);
          remise=(result*10)/100;
          result=result-remise;
          printf("Le montant total apres remise supplémentaire:%5.0f Euros\n",result);
          break;
      default:
          break;
     }
     printf("\n\n");
     printf("________________________ PAIEMENT_________________________\n\n");
     printf("Paiement par espece seulement disponible!\n");
     printf("Quel sera le montant de votre paiement?\n");
     scanf("%f",&paiement);
     
     if(paiement<result)
       { printf("Votre paiement est insuffisant!\n");
         while(paiement<result)
         { printf("Entrez un montant plus élevé\n");
           scanf("%f",&paiement);
         }
       }
     else if(paiement==result)
      printf("Aucune monnaie a vous rendre\n");
     else(paiement>result);
     {
       rendu=paiement-result;
       billet100=rendu/100;
       rendu %= 100;
       billet50=rendu/50;
       rendu %= 50;
       billet10=rendu/10;
       rendu %= 10;
       pieces2=rendu/2;
       rendu %= 2;
       pieces1=rendu/1;
       rendu %= 1;
     
     printf("\n______________ MONNAIE RENDUE _____________________\n\n");
     printf("Nombre de billet de 100 Euros: %d\n",billet100);
     printf("Nombre de billet de 50 Euros: %d\n",billet50);
     printf("Nombre de bilet de 10 Euros: %d\n",billet10);
     printf("Nombre de pieces de 2 Euros: %d\n",pieces2);
     printf("Nombre de pieces de 1 Euros: %d\n",pieces1);
     }
     printf("\n\n");
     printf("\t--> code promo pour un futur achat  :\"MANGER DES POMMES!\"\n");
     
     return 0;
    }
     
     float calcul(int nArticle,float prix)
     {float remise=0,result=0;
       if((nArticle>=10) && (nArticle<50))
         {
          remise=(prix*5)/100;
          result=prix-remise;
          result=result*nArticle;
         }
       else if(nArticle>=50)
         {
          remise=(prix*10)/100;
          result=prix-remise;
          result=result*nArticle;
         }
       else
         {
          result=prix*nArticle;
         }
       return result;
     }

  2. #2
    Membre habitué
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2019
    Messages
    108
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2019
    Messages : 108
    Points : 143
    Points
    143
    Par défaut
    Je pense que fgets, atoi, atof devrait faire l'affaire.

    atoi et atof se trouvent dans stdlib.h

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    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 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chris7522 Voir le message
    Bonjour a toutes et a tous
    Bonjour

    Citation Envoyé par chris7522 Voir le message
    Puisque le scanf n'est pas conseillé , je cherche a le remplacer par une fonction plus sécurisé , du genre fgets ou autre chose . Pouvez vous m'apporter votre aide ?
    Il serait bon d'être plus clair sur ce que tu entends par "sécurisée" (au féminin car c'est un adjectif qui s'accorde avec "fonction") car c'est une notion assez large. La sécurité ça peut être "ne pas saisir plus que ce que la zone peut recevoir" ou bien "saisir en masqué pour pas qu'on voie ce que je tape" ou autre. Et peut-être alors qu'il serait bon que tu saches exactement ce qu'on reproche à scanf()...

    Si ton souci c'est "faire saisir un int et pas autre chose", alors moi j'utilise ce genre de technique
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int saisieInt(char *prompt) {
    	char saisie[100];
    	int nb;
    	while (1) {
    		fputs(prompt, stdout);
    		fflush(stdout);
    		fgets(saisie, 100, stdin);
    		if (sscanf(saisie, "%d", &nb) == 1) break;
    		fputs("Mauvaise saisie - Recommencez !!!\n", stdout);
    	}
    	return nb;
    }
    Pas parfait parfait car ça n'empêche pas le golio moyen de taper 5000 caractères (mon truc boucle en torche jusqu'à ce que tout soit consommé) mais ça va pour les cas les plus standards.

    Et c'est bien évidemment adaptable aux floats ou autres...

    En fait, le vrai souci de scanf() c'est que si ce qu'on tape ne correspond pas exactement à ce qu'il attend, il bloque en laissant tout ce qui ne convient pas dans stdin ce qui va foutre le why dans toutes les saisies suivantes. Et même quand on tape exactement ce qu'il attend (ex "12" pour un int), on valide par <return> et ce <return> ce n'est pas de l'int. Donc même quand on veut être réglo, on ne peut quand-même pas l'être.
    Cette façon de faire consiste simplement à faire saisir en string pour être sûr que stdin soit clean puis ensuite, voir ce qu'on peut faire avec ce qui a été saisi..."
    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]

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Deficient visuel
    Inscrit en
    Mai 2019
    Messages
    196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Deficient visuel

    Informations forums :
    Inscription : Mai 2019
    Messages : 196
    Points : 37
    Points
    37
    Par défaut
    Merci de votre aide .
    Je ne connais pas grand chose au C , puisque débutant , mais a chaque fois que j'écris quelque chose avec cette fonction , on me tombe dessus .
    J'entends souvent parler de buffer overflow , j'en ai compris qu'il était possible d'entrer du code par le biais de scanf et de l'éxecuter ensuite . Bref , j'ai cru comprendre qu'il fallait bannir scanf .

  5. #5
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    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 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chris7522 Voir le message
    mais a chaque fois que j'écris quelque chose avec cette fonction , on me tombe dessus .
    Pas nous. Nous ici, on explique posément le pourquoi des choses.

    Citation Envoyé par chris7522 Voir le message
    J'entends souvent parler de buffer overflow , j'en ai compris qu'il était possible d'entrer du code par le biais de scanf et de l'éxecuter ensuite .
    Oui effectivement. Le buffer overflow c'est rentrer plus d'octets que ceux prévus dans la zone réceptrice et faire en sorte que ce qui dépasse ce soit du code exécutable.
    Et donc typiquement ce type de code char saisie[10]; scanf("%s", saisie) permet cette action.

    Citation Envoyé par chris7522 Voir le message
    Bref , j'ai cru comprendre qu'il fallait bannir scanf .
    Exact. Mais maintenant tu sais pourquoi. Et en passant par fgets() comme je l'ai montré tu évites ce souci et tous ceux liés à l'utilisation d'une fonction qui attend un truc "formaté" alors que ce que tape un humain est tout sauf formaté.
    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]

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Deficient visuel
    Inscrit en
    Mai 2019
    Messages
    196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Deficient visuel

    Informations forums :
    Inscription : Mai 2019
    Messages : 196
    Points : 37
    Points
    37
    Par défaut
    Merci a toi . J'ai bien pris note de ta technique .
    Par contre , ignorant que je suis , je n'arrive pas a mettre en oeuvre ta technique dans le code que j'ai envoyé précédemment .
    Sans pour autant repercuter la technique a l'ensemble du code (peut etre un peu fastidieux), peut tu me montrer ce que cela donne sur le debut du code .
    Merci par avance .

  7. #7
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 435
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 435
    Points : 43 069
    Points
    43 069
    Par défaut
    Tu crée un buffer pour ta chaine, buffer de 50 octets par exemple (choix arbitraire).

    Tu utilises la fonction fgets qui attend la chaine, le nombre de caractère maximal, et le handle du fichier à lire (handle=variable contenant le moyen pour l'OS e gérer le fichier, élement retourné par la fonction fopen ). Cette fonction est prévue pour lire sur un fichier. Il existe une fonction prévue pour lire une chaine sur la console : gets, mais elle ne permet pas de limiter la taille lue.

    Si tu utilises en handle la valeur stdin, fgets lira ce qui est saisie sur la console. stdin est un fichier virtual correspondant à ce qui est lue sur la console.
    Tu dois limiter le nombre de caractère à lire à la taille de ton buffer -1 (donc dans notre cas plus haut 49), ceci afin de laisser la place au caractère \0 finissant la chaine de caractère (voir cours sur les chaines de caractères en C). La lecture s'arrêtera après un retour chariot ou ateinte du nombre max de caractères pouvant être lu.

    Comme tu veux un entier, il te faut ensuite convertir la chaine lue en entier. Il existe une fonction nommée atoi qui fait cela, simple à utiliser, mais ne faisant pas de vérification. Il ne faut donc pas l'utiliser sauf si tu es sûr que ta chaine est fiable (un peu comme l'exemple d'utilisation de sscanf par Sver), ce qui est impossible avec une saisie console. C'est un peu comme scanf, sauf qu'elle ne provoquera pas de risque de buffer overflow mais une valeur non fiable. Tu peux par contre utiliser la fonction strtol. Cette fonction est très intéressante car elle accepte des espaces en début de chaine sans générer d'erreur, elle gère aussi le symbole + ou - . (voir son man)

    Essayes donc de créer un code qui :
    - lit une chaine avec fgets
    - convertit cette chaine en entier vai atol()
    - vérifie la validité de la conversion (voir man de atol)
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  8. #8
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    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 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chris7522 Voir le message
    Sans pour autant repercuter la technique a l'ensemble du code (peut etre un peu fastidieux), peut tu me montrer ce que cela donne sur le debut du code .
    Tu remplaces
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     printf("Quel est votre choix?\n");
     scanf("%d",&choix);
    while((choix!=1)&&(choix!=2))
       {
        printf("Mauvais choix,recommencez\n");
        scanf("%d",&choix);
       }
    par
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    while (1) {
    	choix=saisieInt("Quel est votre choix?");
    	if (choix >=1 && choix <=2) break;
    	printf("Mauvais choix,recommencez\n");
    }

    Citation Envoyé par chrtophe Voir le message
    Tu dois limiter le nombre de caractère à lire à la taille de ton buffer -1 (donc dans notre cas plus haut 49), ceci afin de laisser la place au caractère \0 finissant la chaine de caractère (voir cours sur les chaines de caractères en C).
    Non. fgets() réserve elle-même la place pour stocker le '\0'. Donc tu lui donnes 50 et elle s'arrête d'elle-même à 49. D'où mon exemple où je définis une zone à 100 et je lui passe 100.
    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]

  9. #9
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 435
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 435
    Points : 43 069
    Points
    43 069
    Par défaut
    J'ai relu le man de fgets, et effectivement Sver tu as raison.
    Merci pour la correction.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  10. #10
    Nouveau membre du Club
    Homme Profil pro
    Deficient visuel
    Inscrit en
    Mai 2019
    Messages
    196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Deficient visuel

    Informations forums :
    Inscription : Mai 2019
    Messages : 196
    Points : 37
    Points
    37
    Par défaut
    D'abord merci à tous pour avoir pris le temps de toutes ces explications ! C'est vraiment généreux de votre part.
    Quitte à passer pour un imbécile, je voudrais revenir sur l'échange entre, d'une part dans le main :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    while (1) {
    	choix=saisieInt("Quel est votre choix?");
    	if (choix >=1 && choix <=2) break;
    	printf("Mauvais choix,recommencez\n");
    }
    Et d'autre part dans la fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int saisieInt(char *prompt) {
    	char saisie[100];
    	int nb;
    	while (1) {
    		fputs(prompt, stdout);   /*En paramètre: chaîne de caractères qui va être lue et le flux utilisé pour l'écriture */
    		fflush(stdout);  // synchronise le buffer avec stdout //
    		fgets(saisie, 100, stdin);  // Saisie maximum de 100 caractères depuis stdin
    		if (sscanf(saisie, "%d", &nb) == 1) break;   // Saisie a partir du ...?
    		fputs("Mauvaise saisie - Recommencez !!!\n", stdout);
    	}
    	return nb;
    }
    - L'appel de fonction saisieInt envoie en paramètre, la phrase : Quel est votre choix ? C'est ça ?
    - Le while 1 est ce qu'on appelle une boucle continue qui se répète tant que .... tant que quoi en fait ?
    - Je ne comprends pas trop ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (choix >=1 && choix <=2) break;

  11. #11
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 435
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 435
    Points : 43 069
    Points
    43 069
    Par défaut
    L'appel de fonction saisieInt envoie en parametre , la phrase : Quel est votre choix? , c'est ca ?
    oui.

    while exécute le bloc en dessous tant que la condition entre parenthèse est vrai. Essayes en remplaçant par 255, par 12, et par 0 pour voir ce que ça donne.

    Je ne comprends pas trop ceci :
    if (choix >=1 && choix <=2) break;
    si choix est supérieur ou égal à 1 et (&& est un et logique en C) choix est inférieur ou égal à 2 break est exécuté
    break interrompt le bloc de code en cours (sort de donc de la boucle while, marche aussi dans les boucle for, switch)
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  12. #12
    Nouveau membre du Club
    Homme Profil pro
    Deficient visuel
    Inscrit en
    Mai 2019
    Messages
    196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Deficient visuel

    Informations forums :
    Inscription : Mai 2019
    Messages : 196
    Points : 37
    Points
    37
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (choix >=1 && choix <=2) break;
    Au départ, je souhaitais que la personne me choisisse soit 1 ou soit 2. Pourquoi cette formulation ?
    Et puis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (sscanf(saisie, "%d", &nb) == 1) break;
    Que signifie le ==1 ?

  13. #13
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 435
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 435
    Points : 43 069
    Points
    43 069
    Par défaut
    La fonction scanf retourne le nombre d'éléments mis en correspondance et assignés.
    Dans le if, ce retour est comparé à 1 et si égal break est déclenché.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (sscanf(saisie, "%d", &nb) == 1) break;
    est équivalent à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    int retour;
    retour=sscanf(saisie, "%d", &nb);
    if (retour == 1) break;
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  14. #14
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut
    Bonjour,

    Citation Envoyé par chris7522 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (choix >=1 && choix <=2) break;
    Au départ, je souhaitais que la personne me choisisse soit 1 ou soit 2. Pourquoi cette formulation ?
    Et puis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (sscanf(saisie, "%d", &nb) == 1) break;
    Que signifie le ==1 ?
    Pour la compréhension du ==1 et autres explications; voici un exemple simple que vous devez compiler et tester en espérant qu'avec l'exemple ci-dessous la compréhension serait plus facile.
    À bientôt,

    Code C : 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
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
     
     
    int saisieInt(char *prompt) {
        char saisie[100];
        int nb;
        while (1) {
            fputs(prompt, stdout);   /*En parametre: chaine de caractere qui va etre lue et le flux utilisé pour l'ecriture */
            fflush(stdout);  // synchronise le buffer avec stdout //
            fgets(saisie, 100, stdin);  // Saisie maximum de 100 caracteres depuis stdin
            if (sscanf(saisie, "%d", &nb) == 1) break;   // Saisie a partir du ...?
            fputs("Mauvaise saisie - Recommencez !!!\n", stdout);
        }
        return nb;
    }
     
     
    int f_result( int value ){
        return ( 1 <= value && 2 >= value );
    }
     
     
    int main( void ){
     
        int i = 0;
        (void)puts("Pour commencer voici ce que\n");
        for( i = 0; i < 10; i++ )
            (void)fprintf(stderr, 
                "I = %d et f_result(%d) renvoie = %d\n", 
                i, i, f_result(i));
     
     
        /*    cas du ==  */
        (void)puts("Et voici le cas du ==1\n");
        (void)fprintf(stderr, 
            "D'après vous si f_result(10) me renvoie 1 et que 1 est égale 1 cela est il correcte oui ou non");
     
        i = saisieInt("Tapez 1 pour Oui et 0 pour Non\n");
        if( 1 == i ){
            (void)puts("Raté 1==0 vaut 0 car  1 n'est pas égale à 0 ");
        }else
            (void)puts("Vous avez compris ce que veux dire == ");
        return EXIT_SUCCESS;
    }
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

  15. #15
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 684
    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 684
    Points : 30 973
    Points
    30 973
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chris7522 Voir le message
    - Je ne comprends pas trop ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (choix >=1 && choix <=2) break;
    Tu as remarqué que j'ai écrit "remplace ton code par celui-ci". Cela sous-entend évidemment que ce nouveau code aura le même fonctionnement que le tien bien qu'écrit différemment. Ce détail déjà devrait donc t'aider à comprendre le fonctionnement de ce nouveau code en le comparant avec le tien (comme la pierre de Rosette)...

    Citation Envoyé par chris7522 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (choix >=1 && choix <=2) break;
    Au départ, je souhaitais que la personne me choisisse soit 1 ou soit 2. Pourquoi cette formulation ?
    Quand je code j'essaye aussi de penser au futur probable. Aujourd'hui le choix est entre 1 et 2 mais si demain il est entre 1 et 5, je ne change qu'un caractère dans mon code. Avec ton écriture while((choix!=1)&&(choix!=2)) il faut rajouter && choix != 3 && choix != 4 && choix != 5.
    Bon bien évidemment si après-demain on me demande juste les choix 1, 2 et 7 là fatalement...

    Citation Envoyé par chris7522 Voir le message
    Et puis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (sscanf(saisie, "%d", &nb) == 1) break;
    Que signifie le ==1 ?
    Hey, quand on te donne un code avec des fonctions que tu ne maitrises pas, t'as aussi le droit d'aller tout seul chercher la doc qui explique son fonctionnement...
    Je regarde si sscanf() a bien récupéré un int de la chaine saisie.

    Citation Envoyé par chris7522 Voir le message
    Le while 1 est ce qu'on appelle une boucle continue qui se répète tant que .... tant que quoi en fait ?
    Tant que l'expresison située dans les parenthèses est vraie. Et comme "1" est toujours vrai, cette boucle se répête à l'infini. Autrement dit, on n'en sort que quand on a saisi un int valide.

    C'est une façon de programmer que j'aime bien. Plutôt que d'écrire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    val=saisie()
    while (val incorrecte) {
    	printf("Erreur")
    	val=saisie()
    }
    je préfère
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    while (1) {
    	val=saisie()
    	if (val correcte) break;
    	printf("Erreur");
    }
    Ainsi j'évite cette bête répétition de saisie ce que je trouve plus élégant. Toutefois certains puristes extrémistes limite inquisition refusent le break et te diront que la première écriture est bien plus conforme aux tables de la loi de la méthode Warnier qu'on enseignait à grand-papi...

    Citation Envoyé par sambia39 Voir le message
    fgets(saisie, 100, stdin); // Saisie maximum de 100 99 caracteres depuis stdin
    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]

  16. #16
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    543
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 543
    Points : 1 745
    Points
    1 745
    Par défaut
    Rectificatif, je ne suis pas l'auteur de ces instructions j'ai juste emprunté tel quel

    Citation Envoyé par Sve@r Voir le message
    Citation Envoyé par sambia39 Voir le message
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    fgets(saisie, 100, stdin); //// Saisie maximum de 100 99 caracteres depuis stdin

    Citation Envoyé par chris7522
    Et d'autre part dans la fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int saisieInt(char *prompt) {
        char saisie[100];
        int nb;
        while (1) {
            fputs(prompt, stdout);   /*En paramètre: chaîne de caractères qui va être lue et le flux utilisé pour l'écriture */
            fflush(stdout);  // synchronise le buffer avec stdout //
            fgets(saisie, 100, stdin);  // Saisie maximum de 100 caractères depuis stdin
            if (sscanf(saisie, "%d", &nb) == 1) break;   // Saisie a partir du ...?
            fputs("Mauvaise saisie - Recommencez !!!\n", stdout);
        }
        return nb;
    }
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

  17. #17
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par baragouine Voir le message
    Je pense que fgets, atoi, atof devrait faire l'affaire.

    atoi et atof se trouvent dans stdlib.h
    Citation Envoyé par chrtophe Voir le message
    - convertit cette chaine en entier vai atol()
    - vérifie la validité de la conversion (voir man de atol)
    Non, on n'utilise pas atoi et atof.

    http://manpagesfr.free.fr/man/man3/atoi.3.html
    [La fonction atoi() convertit le début de la chaîne pointée par nptr en entier de type int . Le résultat est identique à un appel
    strtol(nptr, (char **) NULL, 10); à la différence que atoi() ne détecte pas d'erreur.
    http://www.cplusplus.com/reference/cstdlib/atoi/
    On success, the function returns the converted integral number as an int value.
    If the converted value would be out of the range of representable values by an int, it causes undefined behavior. See strtol for a more robust cross-platform alternative when this is a possibility.
    Voir aussi (et surtout ?) https://wiki.sei.cmu.edu/confluence/...ng+to+a+number


  18. #18
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 435
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 435
    Points : 43 069
    Points
    43 069
    Par défaut
    Non, on n'utilise pas atoi et atof.
    Je l'ai indiqué dans ma réponse en #7. J'ai présenté la fonction en précisant qu'il faut utiliser strtol.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  19. #19
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Je te citais car tu parles de vérifier la conversion, ce qui n'est pas possible.

  20. #20
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 435
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 435
    Points : 43 069
    Points
    43 069
    Par défaut
    Je te citais car tu parles de vérifier la conversion, ce qui n'est pas possible.
    Pas avec atoi, mais avec strol.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

Discussions similaires

  1. scanf
    Par bourinator dans le forum C
    Réponses: 8
    Dernier message: 26/09/2003, 14h04
  2. bp scanf...
    Par drKzs dans le forum C
    Réponses: 6
    Dernier message: 18/09/2003, 23h08
  3. PB avec scanf
    Par ché dans le forum C
    Réponses: 6
    Dernier message: 13/08/2003, 07h25
  4. [debutant]la fonction scanf
    Par kalaka dans le forum C
    Réponses: 7
    Dernier message: 01/07/2003, 15h15
  5. Réponses: 6
    Dernier message: 10/09/2002, 03h35

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