Estoy tratando de entender getchar()!=EOF
putchar (8)
Estoy leyendo The C Programming Language y he entendido todo hasta ahora. Sin embargo, cuando me topé con 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);
}
Entiendo la función main()
, la declaración del entero c
y el bucle while. Sin embargo, estoy confundido acerca de la condición dentro del bucle while. ¿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 busco una explicación simple antes de continuar con el libro y confundirme más.
¿Quizás te confundió el hecho de que al ingresar -1 en la línea de comandos no finaliza tu programa? Debido a que 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, al que se accede mediante c.
Luego putchar(c)
recupera este valor, busca la tabla ASCII y vuelve a convertir el carácter, que se imprime.
Supongo que encontrar el valor -1 decimal en la tabla ASCII es imposible, porque la tabla comienza en 0. Por getchar()
tanto, getchar()
tener en cuenta las diferentes soluciones en diferentes plataformas. ¿ getchar()
vez hay una versión getchar()
para cada plataforma?
Simplemente me resulta extraño que este EOF no esté en el ascii regular. Podría haber sido uno de los primeros caracteres, que no son imprimibles. Por ejemplo, el fin de línea está en el ASCII.
¿Qué pasa si transfieres tu archivo de Windows a Linux? ¿Se actualizará automáticamente el carácter del archivo EOF?
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 los caracteres de un archivo, hasta que llegue al final (EOF) representado normalmente por CTRL-Z o CTRL-D.
En la consola: ProgramName < FileName1.txt
Y para crear una copia de lo que se lee de FileName1 puede: ProgramName < FileName1.txt > CopyOfInput.txt
Esto demuestra su programa de múltiples maneras para ayudarlo a comprender.
-Espero que ayude.
El código escrito con las normas C actuales debe ser
#include <stdio.h>
int main(void)
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
El bucle podría reescribirse como
int c;
while (1) {
c = getchar();
if (c != EOF)
putchar(c);
else
break;
}
esto se lee como
- repetir para siempre
- obtenga el siguiente carácter ("byte") de entrada de la entrada estándar y guárdelo en
c
- Si no se produjo una condición excepcional al leer dicho personaje.
- a continuación, envíe el carácter almacenado en
c
en la salida estándar
- a continuación, envíe el carácter almacenado en
- más
- romper el bucle
- obtenga el siguiente carácter ("byte") de entrada de la entrada estándar y guárdelo en
Muchos lenguajes de programación manejan condiciones excepcionales al generar excepciones que rompen el flujo normal del programa. C no hace tal cosa. En su lugar, 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 consultar en la documentación de la función dada. En el caso de getchar
, la documentación del estándar C11 dice ( C11 7.21.7.6p3 ):
- La función
getchar
devuelve el siguiente carácter del flujo de entrada al que apuntastdin
. Si la transmisión está al final del archivo, el indicador de finalización de la transmisión se establece ygetchar
devuelveEOF
. Si se produce un error de lectura, se establece el indicador de error para la transmisión ygetchar
devuelveEOF
.
En otra parte, se indica que EOF
es una constante entera que es <0, y cualquier valor de retorno ordinario es> = 0 - el unsigned char
extendido en cero a un int
.
El flujo al final del archivo significa que toda la entrada se ha consumido. Para la entrada estándar, es posible hacer esto desde el teclado escribiendo Ctrl + D en los terminales Unix / Linux y Ctrl + 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 hacerlo desde el teclado; luego, el final del archivo se señalaría siempre 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 hacer que getchar
devuelva EOF
: se alcanzó el final del archivo o se produjo un error real. Esto no se puede deducir del valor de retorno solo. En su lugar debes usar 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
definida por <errno.h>
contendría el código de error; La función perror
se puede usar para mostrar automáticamente un mensaje de error legible por humanos con un prefijo. Así podríamos ampliar el ejemplo para
#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 la entrada aquí tiene búfer de línea, por lo que la entrada no se intercala dentro de la línea con salida).
Del mismo modo, podemos obtener el mismo efecto utilizando una tubería.
% echo Hello world | ./a.out
Hello world
end-of-file reached
Para desencadenar un error es un poco más complicado. En las carcasas bash
y zsh
, la entrada estándar se puede cerrar para que no provenga de ninguna parte, agregando <&-
a la línea de comando:
% ./a.out <&-
An error occurred. errno set to 9
Human readable explanation: Bad file descriptor
El descriptor de archivo incorrecto , o EBADF
significa que la entrada estándar - número de descriptor de archivo 0 no era válida, 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 configure 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
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 redireccionando la salida estándar a /dev/full
, sin embargo, hay un gotcha, ya que la salida estándar tiene un búfer, tenemos que escribir lo suficiente para que el búfer se vacíe de inmediato y no al final del programa. Obtenemos infinitos bytes de /dev/zero
:
% ./a.out < /dev/zero > /dev/full
putchar failed: No space left on device
PS: es muy importante utilizar siempre una variable de tipo int
para almacenar el valor de retorno de getchar()
. A pesar de que lee un carácter , el uso de caracteres signed
/ unsigned
/ plain char
siempre es incorrecto .
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
}
}
El carácter EOF
se recibe cuando no hay más entrada. El nombre tiene más sentido en el caso en que la entrada se lee de un archivo real, en lugar de la entrada del usuario (que es un caso especial de un archivo).
main
debe escribirse como int main(void)
.] getchar() función getchar() lee un carácter del teclado (es decir, stdin
)
En la condición dentro del bucle while
dado, se llama a getchar()
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 like un archivo. Es decir, la entrada está en búfer. La entrada permanecerá en el búfer hasta que 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 lo que fue leído 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
normalmente significa teclado). Y la salida es lo que proporcionamos como entrada.
La entrada que proporcionamos es de lectura carácter por carácter y se trata como caracteres, incluso si los damos como números.
getchar()
devolverá EOF
solo si se llega al final del archivo. El ''archivo'' que nos ocupa aquí es el propio stdin
(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 . Así que no hay EOF
.
Si proporcionamos más entradas de las que getchar()
puede manejar a la vez (antes de getchar()
como entrada presionando Intro), los valores adicionales aún se almacenarán en el búfer de entrada sin consumir. El getchar()
leerá el primer carácter de la entrada, lo almacenará en c and print
c with
putchar (c) `.
Durante la siguiente iteración del bucle while, los caracteres adicionales dados durante la iteración anterior que todavía están en la stdin
se toman durante while ((c = getchar()) != EOF)
con la parte c=getchar()
. Ahora se repite el mismo proceso hasta que no queda nada en el búfer de entrada.
Esto hace que parezca que putchar()
está devolviendo una cadena en lugar de un solo carácter a la vez si se da más de un carácter como entrada durante una iteración.
Por ejemplo: si la entrada era
abcdefghijkl
la salida hubiera sido la misma
abcdefghijkl
Si no desea este comportamiento, puede agregar fflush(stdin); Justo después del putchar(c);
. Esto hará que el bucle imprima solo el primer carácter en la entrada provista durante cada iteración.
Por ejemplo: si la entrada era
adgbad
sólo se imprimirá un.
La entrada se envía a stdin
solo después de presionar enter.
getchar() es el opuesto de getchar()
. Escribe la salida en el flujo de salida estándar ( stdout
, generalmente 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.
Sin embargo, es probable que no pueda salir del bucle give while normalmente. El búfer de entrada se vaciará (para mostrar en la salida) tan pronto como algo llegue a través del teclado y el stdin
no dará EOF
.
Para salir manualmente del bucle, EOF
puede enviarse usando el teclado presionando ctrl + D en Linux y
Ctrl + Z en Windows
p.ej:
while ((c = getchar()) != EOF)
{
putchar(c);
fflush(stdin);
}
printf("/nGot past!");
Si presiona la combinación de teclas para dar EOF
, el mensaje ¡ Got past!
se mostrará antes de salir del programa.
Si la stdin
no está vacía, deberá presionar esta combinación de teclas dos veces. Una vez para borrar este búfer y luego para simular EOF
.
EDITAR: El par de paréntesis adicional alrededor de c = getchar()
en while ((c = getchar()) != EOF)
es asegurarse de que el valor devuelto por getchar()
se asigna primero a c
antes de que ese valor se compare con EOF
.
Si este paréntesis adicional no estuviera allí, la expresión habría sido efectivamente while (c = (getchar() != EOF) )
lo que hubiera significado que c
podría tener uno de los 2 valores: 1
(para verdadero) o 0
(para falso) que obviamente no es lo que se pretende.
getchar()
es una función que lee un carácter de la entrada estándar . EOF
es un carácter especial utilizado en C para indicar que se ha alcanzado el FIN DE ARCHIVO .
Por lo general, obtendrá un carácter EOF
que regresa de getchar()
cuando su entrada estándar es distinta de la consola (es decir, un archivo).
Si ejecuta su programa en unix como este:
$ cat somefile | ./your_program
Luego, su getchar()
devolverá todos los caracteres en somefile
y EOF
tan pronto como finalice somefile
.
Si ejecuta su programa de esta manera:
$ ./your_program
Y envíe un EOF
través de la consola (presionando CTRL+D
en Unix o CTRL + Z en Windows), entonces getchar()
también devolverá EOF
y la ejecución finalizará.
getchar()
Obtiene un carácter de 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. El valor de EOF
es por defecto -1
.
((c = getchar()) != EOF)
Mientras el valor se mantenga diferente a EOF
o, en otras palabras, mientras la condición se mantenga, el ciclo continuará iterando. Una vez que el valor se convierta en EOF
el valor de toda la condición será 0
y romperá el bucle.
Los paréntesis adicionales alrededor de c = getchar()
son para el compilador, para enfatizar que realmente queríamos hacer una tarea dentro de la condición, porque generalmente asume que usted quería escribir ==
y le advierte.
main() {
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
Así que todo el código realmente hace eco de lo que ingresas. Asigna el valor de los caracteres a c
dentro de la condición y luego lo devuelve al cuerpo del bucle, finalizando solo cuando se detecta el final del archivo.
main(){
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
En realidad, c = getchar () proporciona el carácter que el usuario ingresa en la consola y ese valor se verifica con EOF que representa el final del archivo. EOF se encuentra al final del archivo. (c = getchar ())! = EOF es equivalente a c! = EOF. Ahora creo que esto es mucho más fácil. Si tiene alguna duda, hágamelo saber.