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.

29
demandé sur J...S 2012-05-23 17:21:03

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) .]
25
répondu Oliver Charlesworth 2012-05-23 13:31:02

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.

15
répondu Pablo Santa Cruz 2015-06-30 13:41:47

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?

4
répondu Pedro Norwego 2012-10-22 04:20:24

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
    • else
      • sortir de la boucle

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 ):

  1. la fonction getchar renvoie le caractère suivant de l'entrée stream pointé par stdin . Si le flux est à la fin du fichier, l'indicateur de fin de fichier pour le flux est défini et getchar retourne EOF . Si une erreur de lecture se produit, l'indicateur d'erreur pour le flux est défini et getchar retourne EOF .

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é .

3
répondu Antti Haapala 2017-08-09 05:56:52

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.

2
répondu J...S 2017-08-08 16:31:42

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.

0
répondu Finding Nemo 2 is happening. 2012-05-24 06:02:18
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.

0
répondu Shivam Goel 2016-06-19 14:25:05
 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.

0
répondu Darinka Zobenica 2017-08-08 17:47:51