scanf(" %[^\n]",line);
Un de mes amis a suggéré que l'utilisation de fgets()
pour lire une ligne en entrée serait une bien meilleure idée que d'utiliser scanf()
comme dans la déclaration ci-dessus. Est-il justifié?
char * fgets ( char * str, int num, FILE * stream );
est sûr à utiliser car il évite débordement de tampon problème, il scanne seulement num-1
nombre de caractères.
Lit les caractères du flux et les stocke en tant que chaîne C dans str jusqu'à ce que (num-1) caractères soient lus ou soit une nouvelle ligne ou la fin du fichier soit atteinte, selon la première éventualité.
ici le deuxième argument num
est le nombre maximum de caractères à copier dans str (y compris le caractère nul final).
Par exemple, supposons que dans votre code, la capacité d'un tableau de chaînes ne soit que de 5
Caractères comme ci-dessous.
char str[5];
fgets (str, 5, fp); //5 =you have provision to avoid buffer overrun
En utilisant le code ci-dessus, si l'entrée de fp
est plus longue que les caractères 4
, fgets()
lira juste en premier 4
Caractères, puis ajoutera \0
(, et supprimer les autres caractères d'entrée supplémentaires, stocke simplement cinq caractères dans str[]
).
Alors que scanf(" %[^\n]",str);
lira jusqu'à ce que \n
Ne soit pas trouvé et si la chaîne d'entrée est plus longue, alors 4
Caractères scanf()
provoquera débordement de tampon (car scanf
tentera d'accéder à la mémoire au-delà de l'index max 4
dans str[]
).
La FAQ C contient des explications détaillées sur le problème de scanf
:
Plus généralement,
scanf
est conçu pour une entrée relativement structurée et formatée (son nom est en fait dérivé de "scan formaté"). Si vous faites attention, il vous dira s'il a réussi ou échoué, mais il ne peut vous dire qu'environ où il a échoué et pas du tout comment ni pourquoi. Vous avez très peu d'occasions de récupérer des erreurs.
voir ici pour plus de détails.
Autrement dit: oui, fgets
est un meilleur choix.
J'ai regardé votre spécificateur de format scanf
et j'ai été mystifié. Comprendre exactement ce qu'il fait nécessite un certain temps pour lire les pages man
.
De plus, votre code scanf
est sensible aux dépassements de tampon.
Restez simple et vous réduirez les coûts de maintenance et éviterez les bogues difficiles à trouver!
fgets
sera mieux que cela scanf
. Il peut y avoir des problèmes avec scanf
comme indiqué dans OP
1) débordement de tampon comme suggéré par @Grijesh
2) éventuellement suivant scanf
après cela ne fonctionnera pas car la nouvelle ligne est laissée dans le flux d'entrée. (Si vous manquez un espace vide)
Oui, fgets est le moyen le plus sûr et le plus sûr de lire une ligne à partir de l'entrée standard.
De plus il y aura plus de lisibilité dans le code. Regardez la déclaration scanf que vous avez donnée.
Toute deuxième personne qui le verra sera complètement confuse. Mais alors qu'il y aura plus de lisibilité pour les fgets et c'est facile à comprendre.