Estoy tratando de entender getchar() != EOF

13 minutos de lectura

avatar de usuario
Pablo Bernasconi

Estoy leyendo El lenguaje de programación C y he entendido todo hasta ahora. Sin embargo, cuando me encontré con el getchar() y putchar()no pude entender cuál es su uso y, más específicamente, qué hace el siguiente código.

main()
{
    int c;
    while ((c = getchar()) != EOF)
       putchar(c);
}

Yo entiendo el main() función, la declaración del entero c y el while lazo. Sin embargo, estoy confundido acerca de la condición dentro de la while lazo. ¿Cuál es la entrada en este código C y cuál es la salida?

Lo siento si esta es una pregunta básica y estúpida, pero solo estoy buscando una explicación simple antes de continuar con el libro y confundirme más.

  • Simplemente repite lo que escribes en la terminal. Hasta que llegue al código de control de fin de entrada. Ctrl+Z en Windows, Ctrl+D en *nix.

    -Hans Passant

    23 de mayo de 2012 a las 13:26

avatar de usuario
Oliver Charlesworth

Este código se puede escribir más claramente como:

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
    }
}

los EOF el carácter se recibe cuando no hay más entradas. El nombre tiene más sentido en el caso de que la entrada se lea desde un archivo real, en lugar de la entrada del usuario (que es un caso especial de un archivo).


[As an aside, generally the main function should be written as int main(void).]

  • @TheGameiswar, lea mi nueva incorporación también.

    – Antti Haapala — Слава Україні

    9 de agosto de 2017 a las 5:48

  • EOF no es un personaje.

    – Ayxan Haqverdili

    21 de julio de 2019 a las 10:35

avatar de usuario
pablo santa cruz

getchar() es una función que lee un carácter de entrada estándar. EOF es un caracter especial usado en C para afirmar que el FIN DEL DOCUMENTO ha sido conseguido.

Por lo general, obtendrá un EOF personaje que regresa de getchar() cuando su entrada estándar no es consola (es decir, un archivo).

Si ejecuta su programa en Unix así:

$ cat somefile | ./your_program

Entonces tu getchar() devolverá cada carácter en somefile y EOF tan pronto como somefile termina

Si ejecuta su programa de esta manera:

$ ./your_program

y enviar un EOF a través de la consola (pulsando CTRL+D en Unix o CTRL+Z en Windows), luego getchar() también regresará EOF y la ejecución terminará.

  • Buen ejemplo de polimorfismo usando getchar(). Lee desde el archivo (entrada). Lee desde el teclado (entrada)

    – sobrecambio

    21 de junio de 2015 a las 10:24


  • Usted puede incluso ./your_program < input_file

    – Desarrollo

    4 de noviembre de 2016 a las 7:35

avatar de usuario
Antti Haapala — Слава Україні

El código escrito con los estándares C actuales debe ser

#include <stdio.h>

int main(void)
{
    int c;
    while ((c = getchar()) != EOF)
       putchar(c);
}

El bucle se puede reescribir como

int c;
while (1) {
    c = getchar();
    if (c != EOF)
        putchar(c);
    else
        break;
}

esto se lee como

  • repetir para siempre
    • obtener el siguiente carácter (“byte”) de la entrada de entrada estándar y almacenarlo en c
    • si no se produjo ninguna condición excepcional durante la lectura de dicho carácter
      • a continuación, salida el carácter almacenado en c dentro salida estándar
    • demás
      • romper el bucle

Muchos lenguajes de programación manejan condiciones excepcionales a través de levantando excepciones que rompen el flujo normal del programa. C no hace tal cosa. En cambio, las funciones que pueden fallar tienen un valor de retorno y cualquier condición excepcional se señala con un valor de retorno especial, que debe verificar en la documentación de la función dada. En caso de getcharla documentación del estándar C11 dice (C11 7.21.7.6p3):

  1. los getchar La función devuelve el siguiente carácter del flujo de entrada al que apunta stdin. Si la secuencia está al final del archivo, el indicador de fin de archivo para la secuencia se establece y getchar devoluciones EOF. Si ocurre un error de lectura, el indicador de error para la transmisión se establece y getchar devoluciones EOF.

Se afirma en otra parte que EOF es una constante entera que es < 0, y cualquier valor de retorno normal es >= 0 – el unsigned char cero extendido a un int.

La secuencia que se encuentra al final del archivo significa que se ha consumido toda la entrada. Para la entrada estándar, es posible hacer esto desde el teclado escribiendo control+D en terminales Unix/Linux y control+Z en las ventanas de la consola de Windows. Otra posibilidad sería que el programa recibiera la entrada de un archivo o una tubería en lugar de un teclado; luego, el final del archivo se señalaría cada vez que esa entrada se consumiera por completo, es decir

cat file | ./myprogram

o

./myprogram < file

Como dice el fragmento anterior, en realidad hay dos condiciones diferentes que pueden causar getchar regresar EOF: ya sea el fin del documento fue alcanzado, o se produjo un error real. Esto no se puede deducir solo del valor de retorno. En su lugar, debe utilizar las funciones feof y ferror. feof(stdin) devolvería un valor verdadero si se llegara al final del archivo en la entrada estándar. ferror(stdin) devolvería verdadero si ocurriera un error.

Si se produjo un error real, la variable errno definido por <errno.h> contendría el código de error; la función perror se puede utilizar para mostrar automáticamente un mensaje de error legible por humanos con un prefijo. Así podríamos ampliar el ejemplo a

#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('?');
    }
}

Para activar el final del archivo, uno usaría Ctrl+D (aquí se muestra como ^D) en una nueva línea en Linux:

% ./a.out
Hello world
Hello world
^D
end-of-file reached

(Observe cómo el aporte aquí tiene un búfer de línea, por lo que la entrada no se intercala dentro de la línea con la salida).

Del mismo modo, podemos obtener el mismo efecto mediante el uso de una canalización.

% echo Hello world | ./a.out
Hello world
end-of-file reached

Activar un error es un poco más complicado. En bash y zsh shells la entrada estándar puede ser cerrado para que no venga de ningún lado, agregando <&- a la línea de comando:

% ./a.out <&-
An error occurred. errno set to 9
Human readable explanation: Bad file descriptor

descriptor de archivo incorrectoo EBADF significa que el entrada estándar – el descriptor de archivo número 0 no era válido, ya que no se abrió en absoluto.

Otra forma divertida de generar un error sería leer la entrada estándar de un directorio – esto hace que errno se establezca en EISDIR en Linux:

% ./a.out < / 
An error occurred. errno set to 21
Human readable explanation: Is a directory

En realidad, el valor de retorno de putchar también debe verificarse; también devuelve EOF en caso de error, o el carácter escrito:

while ((c = getchar()) != EOF) {
    if (putchar(c) == EOF) {
        perror("putchar failed");
        exit(1);
    }
}

Y ahora podemos probar esto redirigiendo la salida estándar a /dev/full – sin embargo, hay un error – dado que la salida estándar está almacenada en búfer, debemos escribir suficiente para hacer que el búfer se vacíe de inmediato y no al final del programa. Obtenemos cero bytes infinitos de /dev/zero:

 % ./a.out < /dev/zero > /dev/full
 putchar failed: No space left on device

PD: es muy importante usar siempre una variable de tipo int para almacenar el valor de retorno de getchar(). Aunque lea un personajeutilizando signed/unsigned/simple char siempre esta mal

  • @TonyTannous tiene que aprovechar la recompensa 😀

    – Antti Haapala — Слава Україні

    8 de agosto de 2017 a las 22:58

  • Gracias por tu esfuerzo y ayuda

    – TheGameiswar

    9 de agosto de 2017 a las 5:49

avatar de usuario
pedro noruego

¿Quizás se confundió por el hecho de que ingresar -1 en la línea de comando no finaliza su programa? Porque getchar() lee esto como dos caracteres, – y 1. En la asignación a c, el carácter se convierte al valor numérico ASCII. Este valor numérico se almacena en alguna ubicación de memoria, a la que se accede mediante c.

Luego putchar(c) recupera este valor, busca la tabla ASCII y vuelve a convertirlo en carácter, que se imprime.

Supongo que encontrar el valor -1 decimal en la tabla ASCII es imposible, porque la tabla comienza en 0. Entonces getchar() tiene que dar cuenta de las diferentes soluciones en diferentes plataformas. tal vez hay un getchar() versión para cada plataforma?

Simplemente me parece extraño que este EOF no esté en el ascii normal. Podría haber sido uno de los primeros personajes, que no son imprimibles. Por ejemplo, Fin de línea está en ASCII.

¿Qué sucede si transfiere su archivo de Windows a Linux? ¿Se actualizará automáticamente el carácter del archivo EOF?

avatar de usuario
J…S

obtener char() función lee un carácter del teclado (es decir, stdin)

En la condición dentro de lo dado while lazo, getchar() se llama antes de cada iteración y el valor recibido se asigna al entero c.

Ahora, debe entenderse que en C, la entrada estándar (stdin) es como un archivo. es decir, la entrada se almacena en búfer. La entrada permanecerá en el búfer hasta que realmente se consuma.
stdin es en realidad el flujo de entrada estándar.

getchar() devuelve el siguiente valor disponible en el búfer de entrada.

El programa esencialmente muestra todo lo que se leyó desde el teclado; incluyendo espacios en blanco como \n (nueva línea), espacio, etc.

es decir, la entrada es la entrada que el usuario proporciona a través del teclado (stdin generalmente significa teclado). Y la salida es lo que proporcionemos como entrada.

La entrada que proporcionamos se lee carácter por carácter y se trata como caracteres incluso si los damos como números.

getchar() regresará EOF solo si se llega al final del archivo. El ‘archivo’ que nos ocupa aquí es el stdin mismo (entrada estándar).

Imagine un archivo existente donde se almacena la entrada que proporcionamos a través del teclado. Eso es stdin. Este ‘archivo’ es como un archivo infinito. entonces no EOF.

Si proporcionamos más información que esa getchar() puede manejar a la vez (antes de darlo como entrada presionando enter), los valores adicionales aún se almacenarán en el búfer de entrada sin consumir. los getchar() leerá el primer carácter de la entrada, lo almacenará en c and printCwithputchar(c)`.

Durante la siguiente iteración del while bucle, los caracteres adicionales dados durante la iteración anterior que todavía están en stdin se toman durante while ((c = getchar()) != EOF) con el c=getchar() parte. Ahora se repite el mismo proceso hasta que no quede nada en el búfer de entrada.

Esto hace que parezca como si putchar() está devolviendo una cadena en lugar de un solo carácter a la vez si se proporciona más de un carácter como entrada durante una iteración.

Por ejemplo: si la entrada fue
abcdefghijkl

la salida hubiera sido la misma
abcdefghijkl

Si no desea este comportamiento, puede agregar fflush(stdin); justo después de la putchar(c);. Esto hará que el bucle imprima solo el primer carácter de la entrada proporcionada durante cada iteración.

Por ejemplo: si la entrada fue
adgbad

solamente a será impreso.

La entrada se envía a stdin solo después de presionar enter.

poner () es lo contrario de getchar(). Escribe la salida en el flujo de salida estándar (stdoutnormalmente el monitor).


EOF
no es un carácter presente en el archivo. Es algo devuelto por la función como un código de error.

Probablemente no podrá salir de la entrega. while bucle normalmente sin embargo. El búfer de entrada se vaciará (para mostrarlo en la salida) tan pronto como entre algo a través del teclado y el stdin no daré EOF.

Para salir manualmente del bucle, EOF se puede enviar usando el teclado presionando
control+D en Linux y
control+Z en ventanas

p.ej:

while ((c = getchar()) != EOF)
{

   putchar(c);
   fflush(stdin);
}
printf("\nGot past!");

Si presiona la combinación de teclas para dar EOFel mensaje Got past! se mostrará antes de salir del programa.

Si stdin es no ya vacío, tendrás que pulsar dos veces esta combinación de teclas. Una vez para borrar este búfer y luego para simular EOF.

EDITAR: El par extra de paréntesis alrededor c = getchar() en while ((c = getchar()) != EOF) es asegurarse de que el valor devuelto por getchar() se asigna primero a c antes de que el valor se compara con EOF.

Si este paréntesis adicional no estuviera allí, la expresión efectivamente habría sido while (c = (getchar() != EOF) ) lo que hubiera significado que c podría tener cualquiera de 2 valores: 1 (por cierto) o 0 (por falso) que obviamente no es lo que se pretende.

avatar de usuario
J…S

 getchar()

obtiene un carácter de la entrada.

 c = getchar()

El valor de esta asignación es el valor del lado izquierdo después de la asignación, o el valor del carácter que se ha leído. Valor de EOF es por defecto -1.

 ((c = getchar()) != EOF)

Siempre que el valor siga siendo algo distinto de EOF o, en otras palabras, mientras la condición se mantenga verdadera, el ciclo continuará iterando. Una vez que el valor se vuelve EOF el valor de la condición total será 0 y se romperá el bucle.

Los paréntesis adicionales alrededor c = getchar() son para el compilador, para enfatizar que realmente queríamos hacer una asignación dentro de la condición, porque generalmente asume que desea escribir == y te avisa.

 main() {
     int c;
     while ((c = getchar()) != EOF)
         putchar(c);
 }

Entonces, todo el código en realidad refleja lo que ingresaste. Asigna el valor de los caracteres a c dentro de la condición y luego lo devuelve al cuerpo del ciclo, finalizando solo cuando se detecta el final del archivo.

avatar de usuario
Buscando a Nemo 2 está sucediendo.

De manera similar a la | El comando de tubería anterior puede usar la redirección en su sistema para utilizar el código anterior para mostrar todo el contenido de caracteres de un archivo, hasta que llegue al final (EOF) representado por CTRL-Z o CTRL-D generalmente.

En consola:
ProgramName < FileName1.txt

Y para crear una copia de lo que se lee de FileName1 puedes:
ProgramName < FileName1.txt > CopyOfInput.txt

Esto demuestra su programa de múltiples maneras para ayudar a su comprensión.

-Espero que ayude.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad