vérifiez si l'entrée est un nombre et si pas de retour à l'entrée
Donc, je suis nouveau sur ce site et je suis nouveau en programmation. Je suis à mon premier livre, et mon papa a donné un "travail", il n'en connaît pas les codes pour faire ce que ce, mais je veux le faire. Donc, ici, c'est ce que je veux faire:
Je veux créer un programme comme une calculatrice où vous entrez une valeur et une valeur de B, puis le programme affiche le résultat de A + B. je l'ai fait, le problème est que si je saisie d'un caractère le programme continue à lire les autres codes. Voici ce que j'ai écrit, vous comprendrez peut-être mieux.
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
void main(void)
{
int val_a;
int val_b;
int result;
printf("Write a number A=");
scanf("%d", &val_a);
if(isdigit(val_a))
{
printf("\nWrite a number B=");
scanf("%d", &val_b);
}
else
printf("\nI said number.\n");
result = val_a + val_b;
printf("%d + %d = %d", val_a, val_b, result);
getch();
printf("3[2J"); \\ to clear the screen
}
Donc ce que je veux, c'est que le programme va revenir à l'endroit où je dois entrer le numéro A.
J'ai trouvé sur google à propos des étiquettes, mais je n'ai rien compris :D. Peut-être que quelqu'un peut poster un exemple de ce que je veux donc je peux l'étudier.
Dois-je écrire mon nom? Peut-être que la prochaine fois 😛
PS: j'espère que quelqu'un trouvera une erreur de DÉBUTANT dans ce que j'ai écrit et me dire à ce sujet. :prier:
- Savez-vous ce qu'est un
do...while
déclaration est? - Quand vous dites "saisie d'un caractère" voulez-vous dire d'entrée d'un caractère non numérique?
- Je ne sais pas ce qu'est un " do...while est. Je pense que c'est dans les prochaines leçons dans mon livre de C.
- Pouvez-vous être plus précis? Je ne comprends pas ce que tu veux dire.
Vous devez vous connecter pour publier un commentaire.
Critique
Si vous travaillez sur Windows.
Le type de retour de
main()
devrait êtreint
, même si vous trouverez beaucoup d'exemples du contraire.Vous devriez être en testant la valeur de retour de
scanf()
pour voir si elle est capable de lire un nombre ou pas.Ce test 'marche', mais il vérifie si le nombre entré est une valeur dans la plage de 48..57 (qui sont en ASCII, CP1252, Unicode, ISO 8859-1, etc codes pour les chiffres
'0'
à'9'
). Ce n'était probablement pas ce que vous aviez à l'esprit.L'utilisateur a entré un retour à la ligne, de sorte que le saut de ligne en face de l'ot de la
printf()
chaîne de format n'est pas nécessaire, même si elle n'est pas nuisible. Le même commentaire à propos de la vérificationscanf()
s'applique ici aussi.Il est bon de faire la vérification d'erreur. Cependant, vous continuerez même si vous détecter l'erreur. Vous avez vraiment besoin de s'arrêter.
Dans l'ensemble, il est le meilleur pour la fin des lignes avec un saut de ligne. Il vide les données dans le fichier ou de l'écran.
La
printf()
chaîne de format n'est pas portable. Étant donné que vous avez inclus<conio.h>
, vous devriez probablement utiliserclrscr()
(ce qui, probablement, n'envoyer que la séquence d'échappement, ou un équivalent de la terminale). Je ne suis pas convaincu qu'il est nécessaire pour effacer l'écran à la fin du programme, mais je travaille principalement sur les systèmes Unix, pas avec Windows.Étant donné que MSVC est encore un C89 compilateur, vous devez inclure
return 0;
à la fin du programme de retour d'un état de réussite.Réécrit
L'ajout de tous les changements, vous finirais avec:
Lorsque vous avez appris à propos de l'écriture de fonctions, vous pouvez le compresser pour:
La
get_a_number()
fonction n'est pas d'un usage général, fonction, mais il est utile dans ce contexte, puisqu'il encapsule un bout de code commun.C'est une citation de Kernighan & Plauger, "Les Éléments de Style de Programmation".
À l'aide de
atexit()
Le code ci-dessus a été mis à jour pour inclure
getch()
etclrscr()
sur toutes les trajectoires de sortie (et supprimer#include <ctype.h>
, puisque aucune de ces fonctions étaient plus utilisés). C'est une nuisance pour écrire les deux appels de fonction à plusieurs reprises. Une autre façon d'éviter ce problème est d'écrire une fonction qui est appelée lorsque le programme s'arrête; vous enregistrer avec leatexit()
fonction, qui est déclarée dans<stdlib.h>
:Ce code dans
main()
suppose que vous pouvez mélanger des états (commeatexit()
) et les déclarations (commeint val_a
) de façon arbitraire. Qui est permise par l'actuel (2011) et les anciens (1999) versions de la Norme C, mais n'a pas été autorisée par l'original (1989) version de la Norme C. je crois que MSVC adhère à la norme d'origine. Si oui, vous avez probablement besoin d'écrire quemain()
comme:C'est une belle discussion point de savoir si le code à l'intérieur du bloc interne (à l'intérieur des accolades) devrait être mis en retrait d'un niveau supplémentaire ou pas. Vous êtes toujours autorisé à déclarer les variables en début de bloc de code entre accolades, alors, ce qui me permet d'écrire l'appel à
atexit()
, puis de définir et d'utiliser ces variables.Si vous lisez à propos de la programmation Agile, vous verrez que l'un des mantras est:
Le réécrit ci-dessus pour éviter la répétition de l'
getscr()
appels pourrait être considéré comme une application de ce mantra. De la même façon avec lesget_a_number()
fonction; il s'applique à la SEC mantra.D'essayer de nouveau
Si vous souhaitez que le programme allez retour et invite de nouveau si l'utilisateur fait une erreur en leur tapant, alors vous avez besoin de modifier la
get_a_number()
fonction. Et, parce que la fonction se développe considérablement plus complexe, vous certainement besoin à l'aide d'une fonction pour le travail. Vous aussi vous rencontrez un problème avecscanf()
; il ne permet pas d'appliquer un nombre par ligne. Si vous avez tapé1 2
en réponse à la première invite, le premier appel àget_a_number()
de lire le un et le vide, arrêtez d'analyse (et de mettre le dos de blanc pour la réutilisation), et de revenir avec la valeur 1. Le deuxième appel àget_a_number()
serait sortie de l'invite de commandes, mais de retour avec la valeur 2 sans que l'utilisateur en tapant quelque chose de plus. Si ce n'est pas le comportement que vous voulez, alors vous avez à prendre des dispositions pour lire l'intégralité de première ligne et d'analyse pour le numéro, puis jetez le reste. Il y a une autre raison pour inquiéter trop. Si l'utilisateur tapea
au lieu de1
, lescanf()
ne sera jamais rien lu de plus; il va entrer dans une boucle, en constatant que laa
n'est pas valable qu'un chiffre, en renvoyant 0 conversions complète, et votre code sera probablement jusqu'à la fin dans une boucle infinie, d'une demande d'entrée et de lecture de laa
. Ce genre de problème, c'est pourquoi beaucoup de gens (surtout moi) éviter d'utiliserscanf()
.La façon la plus simple d'éviter la plupart des problèmes ci-dessus est avec
fgets()
etsscanf()
:Qui couvre beaucoup de questions. Souvent, c'est une bonne idée de récupérer les données erronées. Vous pouvez le faire avec:
Il utilise 'près de concaténation de chaîne", et indique à l'utilisateur que le programme a reçu, ce qui peut souvent aider l'utilisateur à comprendre quel est le problème.
J'ai utilisé
fputs(prompt, stdout)
au lieu deprintf(prompt)
à la sortie de l'invite de commandes. Soit pourraient être utilisés (printf(prompt) != 0
serait le test), mais il y a un léger avantage àfputs()
parce que si quelqu'un a réussi à contourner votre programme et d'obtenir un%
dans l'invite, leprintf()
voudrais essayer de traiter un argument a pas été adopté, alors quefputs()
ne pas interpréter sa chaîne d'argument à tous. Ici, la différence est négligeable; il peut être raisonnablement soutenu que je suis au-dessus-de compliquer les choses. Mais la sécurité des programmes est aussi quelque chose que vous de fin d'apprentissage, et des techniques telles que "ne pas utiliserprintf(variable)
" peut aider à rendre vos programmes plus résilient. (En fait, la complication est l'explication; le code est assez simple.)Une autre point de discussion est " faut-il être un
fflush()
aprèsfputs()
et avantfgets()
?' Il serait possible d'ajouter un petit "condition"fflush(stdout) == 0 &&
à la boucle de contrôle, mais dans la pratique, il est généralement inutile. Il ne ferait qu'une différence si l'entrée standard est à venir à partir d'autre chose que le terminal et la sortie standard allait à un fichier. Donc, je l'ai laissée.Le compteur dans la boucle empêche les choses vont mal tourné — le programme des sorties plutôt que de traîner éternellement, frustrant l'utilisateur qui ne peuvent pas obtenir les données saisies correctement. Avez-vous déjà eu un programme ouvre une boîte de dialogue dans laquelle vous pouvez seulement frapper le bouton 'OK' (même si sa n'est pas OK) et puis revenir avec la même boîte de nouveau, maintes et maintes et maintes fois? Je ne l'espère pas pour votre bien. J'ai, il me frustre quand il arrive.
Et vous pouvez voir pourquoi il est avantageux d'écrire le code dans
get_a_number()
juste une fois, plutôt que deux fois; ce serait beaucoup de répétition.getc()
fonction (et peut-être leclrscr()
fonction trop), même quand il y a un problème. Aussi, de fuite Windows est surtout un problème dans l'IDE environnements; j'ai tendance à avoir un 'xterm' comme ma Fenêtre et faire tout mon développement en il y, plutôt que dans un IDE. (Et une raison pour ne pas utiliser un IDE, c'est que les programmes que je travail avec juste ne pas se comporter sainement, lorsqu'il est exécuté par une IDE.) Je vais mettre à jour le programme (je l'espère) d'améliorer l'erreur de comportement.scanf()
; si vous tapeza
, il ne sera jamais rien d'utile lorsqu'il est à la recherche d'un numéro. Si vous pouvez vivre avec ce problème (alors que vous êtes en train d'apprendre, vous pouvez probablement), il y a des solutions plus simples. Toutefois, tous mes suggestions construire les uns des autres. Peut-être qu'il est temps pour une vérification de l'état. Avez-vous appris à écrire vos propres fonctions? Si non, alors j'ai été grossièrement-de compliquer les choses pour vous, mais vous aurez probablement à mieux comprendre ce que j'essaie d'enseigner une fois que vous avez appris à propos de l'écriture de vos propres fonctions.Vous devez vérifier si
scanf()
réussi à lire l'entrée il faut lire. En général, vous devriez toujours vérifier après avoir lu que la lecture a été un succès.scanf()
retourne le nombre de réussir à lire les entrées qui, essentiellement, la carte du nombre de spécificateurs de format il pourrait réussir à lire. Par exemple, vous devez vérifier queDe la valeur lue ou peut-être pas être un "chiffre". En général, il n'est probablement pas un chiffre selon
isdigit()
parce que cette fonction ne renvoie vrai pour les valeurs entières des personnages'0'
,'1'
, ...,'9'
. Test siscanf()
pouvait y lire toute sa spécificateurs de format devrait éviter ce problème.Si
scanf()
échoue, vous pouvez lire un caractère (par exemple à l'aidefgetc()
) et essayer à nouveau ou de lire une ligne entière (pas à l'aide degets()
mais en utilisantfgets()
). Vous pouvez également imprimer un message que l'entrée n'était pas ce qui était prévu.Vous avez obtenu le
isdigit
fonction de tout mal. Il est destiné à recevoir un char argument, mais dans votre cas, l'int est converti, déclassé, pourrait-on dire.La fonction est basée sur les codes ASCII des lettres, lien ici. Vous pouvez essayer ce pour voir par vous-même.
En outre, ce que vous avez besoin est un
do{ /* something */} while(boolean);
Vous ne comprenez pas l'utilisation de l'appel isdigit fonction. Elle détermine si un caractère est un chiffre comme '0', '1', '2', etc. Cependant, vous avez déjà converti à l'entrée d'un nombre entier avec la fonction scanf. Donc, il suffit de supprimer l'appel à appel isdigit et, au lieu de vérifier le code de retour de scanf, qui vous dira si l'utilisateur a entré un numéro de série valide.