6
votes

Rincer stdin après chaque entrée - quelle approche n'est pas buggy?

Après Mark Lakata ​​Code> a souligné que la poubelle n'est pas correctement définie dans ma question que je suis venu avec cela. Je garderai cette mise à jour pour éviter les confusions.


J'essaie d'obtenir une fonction que je peux appeler avant une invite d'entrée de l'utilisateur comme printf ("Entrez votre choix :); CODE> suivi d'un scanf code> et assurez-vous que seules les choses entrées après l'invite seront numérisées par scanf code> comme entrée valide. p>

aussi loin que je peux Comprendre la fonction nécessaire est quelque chose qui afflique complètement la saisie standard. C'est ce que je veux. C'est ce que je veux. Donc, pour le but de cette fonction, le "orbage" code> est tout dans l'entrée de l'utilisateur, c'est-à-dire l'entrée de l'utilisateur avant cette entrée Invite de l'utilisateur. p>


en utilisant scanf () code> in c Il y a toujours le problème d'une entrée supplémentaire située dans le tampon d'entrée. Alors je cherchais une fonction que je Appelez après chaque appel de Scanf pour remédier à ce problème. J'ai utilisé Ceci , Ce , Ce et Ceci pour obtenir ces réponses p> xxx pré>

Tous les trois travaillent aussi loin que je pouvais trouver par jugement et par les références. Mais avant d'utiliser l'un de ces codes dans tous mes codes, je voulais savoir si les bugs ont des bugs? P>

EDIT: P>

Merci à mark Lakata pour un bogue en 3ème. Je l'ai corrigé dans la question. P>

EDIT2: P>

après Jerry Coffin a> a répondu J'ai testé les premières approches en utilisant ce programme dans Code: Blocs IDE 12.11 Utilisation de GNU GCC Compiler (Version non indiquée dans les paramètres du compilateur). P>

3
3


12 commentaires

Pourquoi est-il marqué avec optimisation?


@ 0x90 Parce que je voulais savoir s'il est optimal et s'il n'est pas possible d'optimiser.


ok alors lisez ce Stackoverflow.com/questions/5638999/...


@ 0x90 La réponse acceptée est bonne lorsque je lisons de grandes entrées à partir de fichiers, mais lorsque je lisons de très petites entrées telles que 1 ou 2 entiers, l'approche de la question liée ne serait pas moins optimale en raison des appels à Malloc, puis de l'analyse des cordes dans les entiers?


Vous pouvez utiliser évitez MALLOC avec déclarer Char BUF [256];


fgets () ou sscanf () ????


Critique constructive: si vous voulez dire que vous voulez dire au moins laissez un commentaire pour l'expliquer


Adem, je pense que vous allez mal ce problème de manière incorrecte. Qu'est-ce que "ordures" entrée? Qu'essayez-vous de lire? Essayez-vous simplement de sauter tout ce qui n'est pas numérique?


@Marklakata J'essaie d'obtenir une fonction que je peux appeler avant une invite d'entrée de l'utilisateur, comme printf ("Entrez votre choix :); suivi un scanf et assurez-vous que Seuls les choses entrées après l'invite seraient numérisées par scanf comme entrée valide. Autant que je puisse comprendre la fonction nécessaire, c'est quelque chose qui flitons complètement d'entrée standard. C'est ce que je veux. Aux fins de cette fonction, le "orbage" est tout dans l'entrée de l'utilisateur, c'est-à-dire l'entrée de l'utilisateur entier avant l'invite de l'utilisateur.


@Marklakata ai tort dans l'analyse du problème ou cela a-t-il ajouté de la clarté à la situation?


Vous ne pouvez pas utiliser Standard C pour faire ce que vous voulez faire. Standard C n'est pas destiné à une entrée d'utilisateur interactive, où l'utilisateur peut taper des informations indésirables avant ou après l'invite le programme. Il y a des moyens autour de cela, mais je ne pense pas que cela vaut la peine d'être effort. La plupart des gens n'utilisent pas de participation de console interactive pour les applications de toute façon, et s'ils le font, ils sont censés ne pas taper des ordures.


Si vous souhaitez "rincer le flux d'entrée", vous devez écrire du code qui accède directement à la console, pas seulement STDIN (qui est toujours tamponné). Il existe des packages tels que malédictions qui font cela ... mais comme je l'ai dit, ce n'est probablement pas ce que vous voulez faire.


5 Réponses :


-1
votes

3 commentaires

getline () est en standard C ++ non standard C. getchar () est dans Standard C. J'ai l'une des méthodes utilisant GetCharar () mais ne comprend pas comment GetChartar () peut être utilisée pour lire des flotteurs d'INT, etc.


Vous devez utiliser sscanf lire à un tampon local et utiliser sscanf , strtol , strtof .


Le code utilise, plus ou moins, le posix getline () < / code> fonction. Le "ou moins" est que la variable de taille tampon ( nbytes ) doit être de type taille_t plutôt que int . En général, vous devriez également libérer le tampon. Ici, cela n'a pas beaucoup d'importance, mais s'il s'agissait d'une fonction plutôt que du programme Main () , cela importerait.



3
votes

Les 2 premiers exemples utilisent une fonctionnalité de Scanf que je ne connaissais même pas existait et je suis sûr que beaucoup d'autres personnes ne savaient pas. Être capable de soutenir une caractéristique à l'avenir est important. Même s'il s'agissait d'une fonctionnalité bien connue, il sera moins efficace et plus difficile de lire la chaîne de format que votre 3ème exemple.

Le troisième exemple a l'air bien.

(Modifier l'historique: j'ai commis une erreur disant que l'ANSI-C n'a pas garanti une évaluation de gauche à droite de && et a proposé un changement. Toutefois, ANSI-C garantit une évaluation de gauche à droite de &&. Je ne suis pas sûr de K & R C, mais je ne trouve aucune référence à elle et personne ne l'utilise de toute façon ...)


7 commentaires

+1 pour le bogue que vous avez souligné dans le 3ème. N'a pas vu ça. Environ 1er et 2ème, ils n'utilisent aucune variable supplémentaire pendant que le 3ème a des appels de fonction répétés. Donc, l'un de ceux-ci ne devrait-il pas être plus efficace?


Regardez les internes de Scanf et vous verrez qu'il est beaucoup moins efficace. GetCharg () (selon la mise en œuvre), d'autre part est très simple et que certaines implémentations pourraient même être inlinées dans votre code, ce qui le rend super rapide.


Qu'entendez-vous par inlined? Je ne connais pas le terme. Est page d'expansion en ligne Wikipedia se réfère à la même chose que vous parlez de?


Est Ceci se référant à la même inlinisation que vous parlez de ? Cela a eu une explication plus simple.


Inline signifie qu'il est écrit comme un appel de fonction, mais c'est plus comme une macrodefine macro. Il n'y a pas de frais générale d'appeler la fonction et l'optimiseur peut également optimiser l'utilisation du registre. C ++ a le mot-clé inline à "Forcer", mais de nombreux compilateurs C le feront automatiquement avec une forte optimisation. La règle numéro un de la programmation est cependant d'obtenir un programme que fonctionne d'abord , puis vous souciez d'optimisation ultérieure.


Le code d'origine était ((c = getchar ())! = '\ N' && c! = Eof) . Ceci fait garantit que l'affectation à C est terminée avant que le deuxième opérande soit évalué; L'opérateur && est Évaluation du court-circuit et introduit un point de séquence. Cela n'a pas changé entre ANSI (C89) et C90.


Je n'ai pas ma copie de K & R1 Handy, mais mon souvenir est que && toujours court-circuité depuis leur introduction. Dans tous les cas, l'IMHO Mangling Code pour soutenir les compilateurs de Pre-C89 n'est pas pratique.



-1
votes

Je pense que si vous voyez soigneusement à droite de cette page, vous verrez de nombreuses questions similaires à la vôtre. Vous pouvez utiliser fflush () sur Windows.


3 commentaires

Ce n'est pas nécessaire. Cela dépend du compilateur que j'utilise sur Windows. J'utilise le code: Blocks IDE avec le compilateur GCC. Il ne permet pas de rincer STDIN en utilisant fflush () . De plus, la question n'est pas spécifique à C sous Windows, il s'agit d'une norme C.


Ce que vous pouvez faire référence à i.e. fflush () Travailler pour Windows serait spécifique aux produits Microsoft s'il est documenté sur MSDN I.e sur Visual Studio ou d'autres produits Microsoft.


fflush est destiné à effacer les tampons de poignée de fichier (c'est-à-dire au niveau du pilote ou au niveau de la mise en mémoire tampon STDIO), pas pour la lecture à la fin de la ligne de texte.



9
votes

Les deux premiers sont subtilement différents: ils lisent et ignorent tous les caractères jusqu'à une nouvelle ligne. Ensuite, le premier saut tous les espaces blancs consécutifs, le prochain caractère que vous lisez sera non-blanc.

La seconde lit et ignore les caractères jusqu'à ce qu'il rencontre une nouvelle ligne puis se lit (et rejette) exactement un autre caractère. .

La différence apparaîtra si vous avez (par exemple) texte double espacé, comme: xxx

supposons que vous lisez quelque part dans le Milieu de la ligne 1. Si vous exécutez ensuite le premier, le caractère suivant que vous avez lu sera le «L» en ligne 2. Si vous exécutez la seconde, le prochain caractère que vous avez lu sera la nouvelle ligne entre la ligne 1 et la ligne 2.

Quant au troisième, si j'allais faire cela du tout, je ferais quelque chose comme: xxx .. .et Oui, cela fonctionne correctement - && force un point de séquence, de sorte que son opérande gauche est évalué en premier. Ensuite, il y a un point de séquence. Ensuite, si et seulement si l'opérande gauche évalué à true , il évalue son opérande droit.

comme pour les différences de performance: puisque vous traitez avec des E / S pour commencer avec , il y a peu de questions raisonnables que toutes ces personnes seront toujours définies par I / O. Malgré sa complexité apparente, scanf (et société) est généralement utilisé et optimisé avec soin sur des années d'utilisation. Dans ce cas, la boucle laminée à la main peut être un peu plus lente (par exemple, si le code pour getchar ne peut pas être étendu en ligne) ou il peut s'agir de la même vitesse. La seule façon dont il reste une chance d'être significativement plus rapide, c'est si la personne qui a écrit votre bibliothèque standard était incompétente.

Aussi de toute la maintenabilité: IMO, quiconque qui prétend savoir C devrait Connaissez la conversion du jeu de numérisation pour scanf . Ce n'est ni nouvelle ni science de fusée. Toute personne qui ne sait pas que ce n'est vraiment pas un programmeur C compétent.


4 commentaires

Votre explication a aidé. Je ne pouvais pas comprendre l'un d'eux avant cela. J'ai essayé les deux. Mais pour une raison quelconque, votre explication n'a pas été tenue et les deux travaillaient dans le cas de test 1 ajouté à la question. Est-ce que c'est due à Scanf S interne? Des conseils concernant le 3ème cas de test?


@Aseembansal: Vos tests sont un peu brisés car % d sauteront d'un espace blanc, ainsi de suite, cela ne fait aucune différence si la principale espace était déjà ignorée. Essayez d'utiliser % c après.


@Jerrycoffin Vous voudrez peut-être reconsidérer votre dernier paragraphe; Vos deux premiers paragraphes donnent sur le fait que si la poubelle consistait simplement à une nouvelle ligne, alors scanf ("% * [^ \ n]% * c"); et scanf ("% * [ ^ \ n] \ n "); arrêter après le premier spécificateur car il n'a pas fait correspondre à rien. Donc ni ne résout le problème. (Une solution serait de casser chacun en deux appels Scanf).


@MattMCnabB: Cela me semble que vous demandez simplement quelque chose que la question ne posait pas (au moins à l'époque - il est sous-jacent édition substantielle depuis). En fin de compte, c'est une question de ce qu'il veut vraiment. Il est certainement vrai que Scanf cessera de numériser dès que toute conversion échoue. S'il souhaite que cela se produise ou veuille la rompre en deux appels pour lire un personnage même s'il n'ya rien précédemment ne semble être ouvert à la question.



1
votes

De nombreuses autres solutions ont le problème qu'elles provoquent le programme de pendre et d'attendre l'entrée lorsqu'il n'y a plus rien à affleurer. En attente de EOF est faux parce que vous n'obtenez pas cela tant que l'utilisateur ferme complètement l'entrée!

sur Linux, les suivants feront un non-bloquant affleurant: xxx

la page de l'homme Linux dit que fflush sur stdin est non standard, mais "la plupart des autres implémentations se comportent la Identique que Linux. "

Le drapeau msg_dontwait est également non standard (il provoque" code> recv pour revenir immédiatement s'il n'y a pas de données à livrer) .


1 commentaires

Les réponses doivent utiliser uniquement les fonctions standard C