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 :

scanf vs fgets


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de _SamSoft_
    Profil pro
    Étudiant
    Inscrit en
    Février 2007
    Messages
    798
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2007
    Messages : 798
    Par défaut scanf vs fgets
    Bonjour, alors voilà comme je suis dans ma période de "remise à niveau en C" j'ai décidé de créer un code illustrant pourquoi il ne faut pas utiliser scanf mais fgets (tout le monde sait ca mais je voulais vous l'illustrer)

    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <stddef.h>
    #include "conio.h"
    int main(void)
    {
      //Exemple with good functions
      char str[256], str2[256];
      puts("Exemple with good functions");
      puts("str =");
      fgets(str, sizeof str, stdin);
      puts("str2=");
      fgets(str2, sizeof str2, stdin);
      if(strcmp (str, str2) == 0)
               puts("str = str2");
      else
               puts("str != str2");
      getch();
      clrscr();
      //Exemple with bad functions
      puts("Exemple with bad functions");
      printf("str=");
      scanf("%s", &str);
      printf("str2=");
      scanf("%s", &str2);
      if(strcmp (str, str2) == 0)
               puts("str = str2");
      else
               puts("str != str2");
      getch();
      return 0;
    }
    Si vous testez en entrant par exemple : "mon texte", aucune différence (visible) n'apparaîtra à l'écran mais testez avec cette chaine de caractères :

    Test numéro 98. Test numéro x0çéà&à=ù$=lpé&às)

    PS: Ceci s'adresse aux gens qui sont encore pour scanf
    En souhaitant que je ne vais pas me faire descendre

  2. #2
    Expert confirmé
    Avatar de Skyounet
    Homme Profil pro
    Software Engineer
    Inscrit en
    Mars 2005
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 6 380
    Par défaut
    Ton scanf est faux, pas de & avec un %s...

    De plus, la principale raison pour laquelle il ne faut pas utiliser scanf avec un %s est simplement parce qu'il n'y a pas de contrôle sur la taille entrée, pouvant provoquer un buffer overflow.

    Ton exemple n'illustre pas ce danger. Et je n'ai d'ailleurs pas tout à fait compris ce qu'il est censé illustrer.

  3. #3
    Membre éclairé Avatar de _SamSoft_
    Profil pro
    Étudiant
    Inscrit en
    Février 2007
    Messages
    798
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2007
    Messages : 798
    Par défaut
    Ayant 15ans et étant en période de remise à niveau, je me concentre sur l'apprentissage intensif

    Je sais juste que mon code sert à montrer qu'on rencontre plus facilement des problèmes avec scanf qu'avec fgets, vous l'avez dit vous même, je me suis trompé avec scanf alors que fgets est plus simple d'utilisation

    Regardez :

    Si vous tapez lors du premier test (celui avec fgets) :

    Test numéro 98. Test numéro x0çéà&à=ù$=lpé&às)

    Deux fois, vous aurez : str = str2

    Si vous effectuez la même manipulation lors du second exempel (celui avec scanf) vous aurez :

    str= str!=str2 (ou un truc dans le genre) donc...

    Code mis à jour :

    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <stddef.h>
    #include "conio.h"
    int main(void)
    {
      //Exemple with good functions
      char str[256], str2[256];
      puts("Exemple with good functions");
      puts("str =");
      fgets(str, sizeof str, stdin);
      puts("str2=");
      fgets(str2, sizeof str2, stdin);
      if(strcmp (str, str2) == 0)
               puts("str = str2");
      else
               puts("str != str2");
      getch();
      clrscr();
      //Exemple with bad functions
      puts("Exemple with bad functions");
      printf("str=");
      scanf("%s", str);
      printf("str2=");
      scanf("%s", str2);
      if(strcmp (str, str2) == 0)
               puts("str = str2");
      else
               puts("str != str2");
      getch();
      return 0;
    }

  4. #4
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par _SamSoft_ Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
      char str[256], str2[256];
     
      //Exemple with bad functions
      puts("Exemple with bad functions");
      printf("str=");
      scanf("%s", str);
    Le problème de scanf() n'est pas que c'est une 'mauvaise fonction' (je rappelle au passage que 'exemple' se dit 'example' en anglais...), mais que la plupart du temps, elle est mal utilisée.

    Ici, par exemple, il n'est fait aucun contrôle de débordement.

    Par contre, il existe un vrai problème avec scanf() et "%s", c'est pour la saisie de textes séparés par des 'blancs' (blank : espace, tabulation, fin de ligne). A ma connaissance, il n'y a pas de solution pour que scanf() ignore qu'un 'blanc' est un séparateur.

  5. #5
    Rédacteur
    Avatar de Vincent Rogier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    2 373
    Détails du profil
    Informations personnelles :
    Âge : 47
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 2 373
    Par défaut
    De plus, la principale raison pour laquelle il ne faut pas utiliser scanf avec un %s est simplement parce qu'il n'y a pas de contrôle sur la taille entrée, pouvant provoquer un buffer overflow.
    Skyrunner, c'est faux car scanf te permet de spéficier la taille du buffer, ce qu'il faut toujours faire avec %s !

    Le soucis, comme le dit Emmanuel Delahaye, c'est la gestion des blancs.

    Sinon, je ne vois pas l'utilité de ce code et de cette démonstration ....
    Vincent Rogier.

    Rubrique ORACLE : Accueil - Forum - Tutoriels - FAQ - Livres - Blog

    Vous voulez contribuer à la rubrique Oracle ? Contactez la rubrique !

    OCILIB (C Driver for Oracle)

    Librairie C Open Source multi-plateformes pour accéder et manipuler des bases de données Oracle

  6. #6
    Expert confirmé
    Avatar de Skyounet
    Homme Profil pro
    Software Engineer
    Inscrit en
    Mars 2005
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 6 380
    Par défaut
    Citation Envoyé par vicenzo Voir le message
    Skyrunner, c'est faux car scanf te permet de spéficier la taille du buffer, ce qu'il faut toujours faire avec %s !

    Le soucis, comme le dit Emmanuel Delahaye, c'est la gestion des blancs.

    Sinon, je ne vois pas l'utilité de ce code et de cette démonstration ....
    Je parlais simplement par défaut, il est vrai qu'en jouant avec les options de scanf on peut faire des choses assez intéressantes, mais le débutant de base, ne se jete pas à bras ouverts dans les pages de man.

  7. #7
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par vicenzo Voir le message
    Skyrunner, c'est faux car scanf te permet de spéficier la taille du buffer, ce qu'il faut toujours faire avec %s !
    Oui, il est possible de gerer la taille des buffer avec le scanf (tout comme il est possible de gerer les blancs), mais c'est relativement complexe a mettre en oeuvre (par rapport a une fonction comme fgets()) et assez facile de l'oublier.
    En conclusion, scanf() n'est certainement pas la fonction la plus adaptee pour saisir une chaine de caractere. Il est largement preferable d'utiliser fgets()

  8. #8
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    Par contre, il existe un vrai problème avec scanf() et "%s", c'est pour la saisie de textes séparés par des 'blancs' (blank : espace, tabulation, fin de ligne). A ma connaissance, il n'y a pas de solution pour que scanf() ignore qu'un 'blanc' est un séparateur.
    C'est possible en jouant avec %[^...]. Par exemple pour ne conserver que \n comme separateur, il faut remplacer %s par %[^\n].
    De meme il est possible de limiter la taille maximale de la saisie.

    Pour plus d'information sur l'utilisation de scanf : Scanf démythifiée.

    Il est tout de meme largement preferable d'utiliser fgets() qui est bien plus simple d'utilisation (et generalement bien mieux utiliser que scanf()).

Discussions similaires

  1. fgets + scanf et gestion des espaces
    Par Yunchi dans le forum Débuter
    Réponses: 7
    Dernier message: 02/03/2009, 15h35
  2. Scanf, fgets et buffer.
    Par SAKDOSS dans le forum Bibliothèque standard
    Réponses: 6
    Dernier message: 15/01/2008, 08h58
  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