J'essaie de comprendre getchar()!= EOF
je suis en train de lire le langage de programmation C et j'ai tout compris jusqu'à présent.
Cependant, lorsque je suis tombé sur les codes getchar()
et putchar()
, Je n'ai pas compris à quoi ils servaient, et plus précisément, ce que fait le code suivant.
main()
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
je comprends la fonction main()
, la déclaration de l'entier c
et la boucle while
. Pourtant, je suis confus au sujet de l'État à l'intérieur de la boucle while
. Qu'est-ce que l'entrée dans ce code C, et quelle est la sortie.
Désolé si c'est une base et question stupide, mais je suis à la recherche d'une explication simple avant de passer dans le livre et de devenir plus confuse.
8 réponses
ce code peut être écrit plus clairement comme:
main()
{
int c;
while (1) {
c = getchar(); // Get one character from the input
if (c == EOF) { break; } // Exit the loop if we receive EOF ("end of file")
putchar(c); // Put the character to the output
}
}
Le EOF
caractère est reçu lorsqu'il n'y a plus d'entrée. Le nom a plus de sens dans le cas où l'entrée est lue à partir d'un fichier réel, plutôt que l'entrée utilisateur (ce qui est un cas particulier d'un fichier).
[De façon générale, la fonction
main
devrait être écrite comme int main(void)
.]
getchar()
est une fonction qui lit un caractère de entrée standard . EOF
est un caractère spécial utilisé dans C pour indiquer que le fin du dossier a été atteint.
habituellement, vous obtiendrez un caractère EOF
revenant de getchar()
lorsque votre entrée standard est autre que la console (c.-à-d., un fichier).
Si vous exécutez votre programme sous unix comme ceci:
$ cat somefile | ./your_program
ensuite votre getchar()
retournera chaque caractère dans somefile
et EOF
dès que somefile
se terminera.
Si vous exécutez votre programme comme ceci:
$ ./your_program
et envoyer un EOF
à travers la console (en tapant CTRL+D
dans Unix ou CTRL+Z dans Windows), puis getchar()
retournera aussi EOF
et l'exécution prendra fin.
peut-être avez-vous été confus par le fait que l'Entrée -1 sur la ligne de commande ne met pas fin à votre programme? Parce que getchar()
lit ceci comme deux caractères, - et 1. Dans l'assignation en c, le caractère est converti en valeur numérique ASCII. Cette valeur numérique est stockée dans une mémoire accessible par C.
puis putchar(c)
récupère cette valeur, regarde la table ASCII et retourne au caractère, qui est imprimé.
je suppose trouver la valeur -1 décimal dans la table ASCII est impossible, parce que la table commence à 0. Donc getchar()
doit tenir compte des différentes solutions sur différentes plateformes. peut-être qu'il y a une version getchar()
pour chaque plateforme?
je trouve étrange que cet EOF ne soit pas dans les ascii réguliers. Il pourrait avoir été l'un des premiers personnages, qui ne sont pas imprimables. Par exemple, End-of-line est dans L'ASCII.
que se passe-t-il si vous transférer votre fichier de windows à linux? Le caractère du fichier EOF sera-t-il automatiquement mis à jour?
le code écrit avec les normes C actuelles devrait être
#include <stdio.h>
int main(void)
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
la boucle pourrait être réécrite comme
int c;
while (1) {
c = getchar();
if (c != EOF)
putchar(c);
else
break;
}
ça se lit comme
- répéter pour toujours
- récupérez le caractère suivant ("byte") de l'entrée entrée standard et stockez-le dans
c
- si aucune condition exceptionnelle s'est produit lors de la lecture de ce personnage
- puis sortie le caractère stocké dans
c
dans sortie standard
- puis sortie le caractère stocké dans
- else
- sortir de la boucle
- récupérez le caractère suivant ("byte") de l'entrée entrée standard et stockez-le dans
de nombreux langages de programmation gèrent des conditions exceptionnelles grâce à soulever des exceptions que brisez le flux normal du programme. C ne fait pas une telle chose. Au lieu de cela, les fonctions qui peuvent échouer ont une valeur de retour et toutes les conditions exceptionnelles sont signalées par une valeur de retour spéciale, que vous devez vérifier à partir de la documentation de la fonction donnée. Dans le cas de getchar
, la documentation de la norme C11 dit ( C11 7.21.7.6p3 ):
- la fonction
getchar
renvoie le caractère suivant de l'entrée stream pointé parstdin
. Si le flux est à la fin du fichier, l'indicateur de fin de fichier pour le flux est défini etgetchar
retourneEOF
. Si une erreur de lecture se produit, l'indicateur d'erreur pour le flux est défini etgetchar
retourneEOF
.
il est dit ailleurs que EOF
est une constante entière qui est < 0, et toute valeur de retour ordinaire est >= 0 - le unsigned char
zéro-étendu à un int
.
le flux étant à la fin du fichier signifie que la totalité de l'entrée a été consommée. Pour l'entrée standard, il est possible de provoquer cela à partir du clavier en tapant Ctrl + D sur les terminaux Unix/Linux et Ctrl + Z dans Windows console windows. Une autre possibilité serait que le programme reçoive l'entrée à partir d'un fichier ou d'un tuyau au lieu du clavier - alors fin du fichier serait signalé chaque fois que cette entrée a été entièrement consommée, c.-à-d.
cat file | ./myprogram
ou
./myprogram < file
comme le fragment ci-dessus dit, Il ya en fait deux conditions différentes qui peuvent causer getchar
à retourner EOF
: soit le fin du fichier a été atteint, ou une erreur réelle s'est produite. Cela ne peut être déduit de la seule valeur de retour. Vous devez plutôt utiliser les fonctions feof
et ferror
. feof(stdin)
retournerait une valeur vraie si la fin du fichier était atteinte sur l'entrée standard. ferror(stdin)
renverrait true si une erreur se produisait.
si une erreur s'est produite, la variable errno
définie par <errno.h>
contiendrait le code d'erreur; la fonction perror
peut être utilisée pour afficher automatiquement un message d'erreur lisible par l'utilisateur avec un préfixe. Nous pourrions ainsi étendre la exemple de
#include <stdio.h>
#include <errno.h> // for the definition of errno
#include <stdlib.h> // for exit()
int main(void)
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
if (feof(stdin)) {
printf("end-of-file reached\n");
exit(0);
}
else if (ferror(stdin)) {
printf("An error occurred. errno set to %d\n", errno);
perror("Human readable explanation");
exit(1);
}
else {
printf("This should never happen...\n");
exit('?');
}
}
pour déclencher la fin du fichier, on utiliserait Ctrl+D (ici affiché comme ^D
) sur une nouvelle ligne sous Linux:
% ./a.out
Hello world
Hello world
^D
end-of-file reached
(notez comment le input ici est doté d'un tampon de ligne, de sorte que l'entrée n'est pas intercalée dans la ligne avec la sortie).
de même, nous pouvons obtenir le même effet en utilisant un pipeline.
% echo Hello world | ./a.out
Hello world
end-of-file reached
pour déclencher une erreur est un peu plus compliqué. Dans les coquilles bash
et zsh
l'entrée standard peut être fermée de sorte qu'elle ne vient de nulle part, en ajoutant <&-
à la ligne de commande:
% ./a.out <&-
An error occurred. errno set to 9
Human readable explanation: Bad file descriptor
mauvais descripteur de fichier , ou EBADF
signifie que le entrée standard - numéro de descripteur de fichier 0 était invalide, car il n'a pas été ouvert du tout.
une Autre façon amusante de générer une erreur serait de lire l'entrée standard à partir d'un répertoire - cela provoque errno pour être réglé à EISDIR
sur Linux:
% ./a.out < /
An error occurred. errno set to 21
Human readable explanation: Is a directory
en fait, la valeur de retour de putchar
doit être vérifiée aussi - il de même
renvoie EOF
par erreur, ou le caractère écrit:
while ((c = getchar()) != EOF) {
if (putchar(c) == EOF) {
perror("putchar failed");
exit(1);
}
}
et maintenant nous pouvons le tester en redirigeant la sortie standard vers /dev/full
- cependant, il y a un gotcha - puisque la sortie standard est tamponnée, nous devons écrire assez pour faire sortir le tampon tout de suite et pas à la fin du programme. Nous obtenons un nombre infini d'octets zéro de /dev/zero
:
% ./a.out < /dev/zero > /dev/full
putchar failed: No space left on device
P.S. il est très important d'utiliser toujours une variable de type int
pour stocker la valeur de retour de getchar()
. Même si on lit un le caractère , en utilisant signed
/ unsigned
/simple char
est toujours erroné .
getchar () fonction lit un caractère du clavier (ie, stdin
)
dans la condition à l'intérieur de la boucle while
donnée, getchar()
est appelé avant chaque itération et la valeur reçue est assignée à l'entier c
.
Maintenant, il faut comprendre que, dans C, l'entrée standard ( stdin
) est comme un fichier. c'est-à-dire que l'entrée est tamponnée. Entrée restez dans le tampon jusqu'à ce qu'il soit réellement consommé.
stdin
est en fait le flux d'entrée standard .
getchar()
renvoie la valeur la plus proche disponible dans le tampon d'entrée.
le programme affiche essentiellement tout ce qui a été lu du clavier; y compris l'espace blanc comme \n
(newline), l'espace, etc.
ie, l'entrée est l'entrée que l'utilisateur fournit via le clavier ( stdin
signifie habituellement clavier).
Et la sortie est ce que nous fournissons comme entrée.
l'entrée que nous fournissons est lue caractère par caractère et traitée comme des caractères même si nous les donnons comme des nombres.
getchar()
retournera EOF
seulement si la fin du fichier est atteinte. Le fichier qui nous intéresse ici est le stdin
lui-même (entrée standard).
Imaginez un fichier existant où l'entrée que nous fournissons via clavier est stocké. C'est stdin
.
Ce 'fichier' est comme un fichier infini . Donc pas de EOF
.
si nous fournissons plus de données que ce que getchar()
peut traiter à la fois (avant de le donner en entrée en appuyant sur ENTRÉE), les valeurs supplémentaires seront encore stockées dans le tampon d'entrée non utilisé.
Le getchar()
Lira le premier caractère de l'entrée, le stockera dans c and print
c with
putchar(c)".
lors de la prochaine itération de la boucle while
, les caractères supplémentaires donnés lors de l'itération précédente qui sont toujours dans stdin
sont pris pendant while ((c = getchar()) != EOF)
avec la partie c=getchar()
.
Maintenant le même processus est répété jusqu'à ce qu'il ne reste plus rien dans le tampon d'entrée.
cela donne l'impression que putchar()
renvoie une chaîne au lieu d'un seul caractère à la fois si plus d'un caractère est donné en entrée pendant itération.
Eg: si input était
abcdefghijkl
la sortie aurait été le même
abcdefghijkl
si vous ne voulez pas de ce comportement, vous pouvez ajouter fflush(stdin); juste après le putchar(c);
.
Ainsi, la boucle n'affichera que le premier caractère de l'entrée fournie. pendant chaque itération.
Eg: si input était
adgbad
seul a
sera imprimé.
l'entrée est envoyée à stdin
seulement après que vous appuyez sur Entrée.
putchar() est le contraire de getchar()
. Il écrit la sortie au flux de sortie standard ( stdout
, généralement le moniteur).
EOF
n'est pas un personnage présent dans le fichier. C'est quelque chose retourné par la fonction comme un code d'erreur.
vous ne serez probablement pas en mesure de sortir de la boucle donner while
normalement cependant. Le tampon d'entrée sera vidé (pour l'affichage de la sortie) dès que quelque chose y entre via le clavier et le stdin
ne donnera pas EOF
.
pour sortir manuellement de la boucle, EOF
peut être envoyé en utilisant le clavier en appuyant
ctrl + D dans Linux et
ctrl + Z dans Windows
par exemple:
while ((c = getchar()) != EOF)
{
putchar(c);
fflush(stdin);
}
printf("\nGot past!");
si vous appuyez sur la combinaison de touches pour obtenir EOF
, le message Got past!
sera affiché avant de quitter le programme.
si stdin
est pas déjà vide, vous devrez appuyer deux fois sur cette combinaison de touches. Une fois pour nettoyer ce tampon et ensuite pour simuler EOF
.
EDIT: la paire supplémentaire de parenthèses autour de c = getchar()
dans while ((c = getchar()) != EOF)
est de s'assurer que la valeur retournée par getchar()
est d'abord assignée à c
avant que valeur est comparée à EOF
.
si ces parenthèses supplémentaires étaient pas là, l'expression aurait effectivement été while (c = (getchar() != EOF) )
ce qui aurait signifié que c
aurait pu avoir l'une des deux valeurs: 1
(pour vrai) ou 0
(pour faux) ce qui n'est évidemment pas ce qui est prévu.
de manière similaire à la commande | pipe ci-dessus, vous pouvez utiliser la redirection sur votre système pour utiliser le code ci-dessus pour afficher tous les contenus de caractères d'un fichier, jusqu'à ce qu'il atteigne la fin (EOF) représenté par CTRL-Z ou Ctrl-D habituellement.
en console:
ProgramName < FileName1.txt
et pour créer une copie de ce qui est lu à partir de FileName1 vous pouvez:
ProgramName < FileName1.txt > CopyOfInput.txt
cela démontre votre programme de plusieurs façons d'aider espérons votre compréhension.
- J'espère que ça aidera.
main(){
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
en fait c=getchar() fournit le caractère que l'utilisateur entre sur la console et cette valeur est vérifiée avec EOF qui représente la fin du fichier . EOF est rencontré au dernier de file. (c = getchar ())!= EOF est équivalent à c != EOF . Maintenant, je pense que c'est beaucoup plus facile . Si vous avez d'autres questions, faites-le-moi savoir.
getchar()
obtient un caractère d'entrée.
c = getchar()
La valeur de cette mission est la valeur de la gauche après la cession, ou la valeur du caractère qui a été lu. La valeur EOF
est par défaut -1
.
((c = getchar()) != EOF)
aussi longtemps que la valeur reste autre que EOF
ou, en d'autres termes, aussi longtemps que la condition reste vraie, la boucle continuera à itérer. Une fois la valeur devient EOF
la valeur de la condition entière sera 0
et il cassera la boucle.
les parenthèses supplémentaires autour de c = getchar()
sont pour le compilateur, pour souligner que nous voulions vraiment faire une tâche à l'intérieur de la condition, parce qu'il suppose habituellement que vous vouliez taper ==
et vous avertit.
main() {
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
donc le code entier renvoie ce que vous avez saisi. Il assigne la valeur des caractères à c
à l'intérieur de la condition, puis la renvoie dans le corps de la boucle, ne se terminant que lorsque la fin du fichier est détectée.