INGRESO Y SALIDA DE DATOS
Cunado se escribe un programa, se debe pensar que lo hacemos para obtener resultados. Por otro lado, no podemos pensar que al ejecutar un programa siempre vamos a obtener el mismo resultado. Un programa requiere que se le ingrese información de modo que a partir de ella se pueda generar un resultado y luego debe se capaz de mostrar ese resultado. Lo que se va a estudiar en este capítulo son los elementos que permiten realizar estas dos labores, las que se conocen como "Instrucciones de entrada y salida de datos" o de "entrada y salida de flujos".
En capítulos anteriores hemos visto que las diferencias entre lo que se hace con el lenguaje C es muy parecida a lo que se hace con el lenguaje C++, sin embargo en materia de entrada y salida de datos se definen herramientas muy distintas para realizar esta labor. Por un lado el Lenguaje C define una serie de funciones através de la biblioteca cstdio (o stdio.h), mientras que el Lenguaje C++ define un conjunto de clases, objetos y sobrecargas a través de la biblioteca iostream. Esto no quiere decir que si estamos programando en C++ tengamos que emplear obligatoriamente los recursos del C++. Ya que C++ es un super conjunto de C, si desarrollamos en C++ podemos emplear los recursos de C como de C++, lo que si debemos cuidarnos es que no los mezclemos, se usa uno o el otro pero nunca ambos a la vez en un programa. Si desarrollamos en C, solo podremos emplear los recursos de C.
En este capítulo analizaremos ambos lenguajes, primero veremos las herramientas proporcionadas por el Lenguaje C y luego las del Lenguaje C++.
INGRESO Y SALIDA DE DATOS DESDE EL LENGUAJE C
Como se dijo anteriormente, para emplear los recursos para el ingreso y salida de datos en el Lenguaje C, debemos incluir en nuestro programa la biblioteca estándar de entrada y salida, que en el caso que el programa se desarrolle en ANSI C la instrucción de pre procesador que se emplee será: #include <stdio.h>, y si estamos desarrollando en C++ y queremos usar estos recursos deberemos indicarlo con la instruccón de pre procesador: #include <cstdio>.
A continuación mostraremos las funciones par realizar esta labor:
FUNCIÓN printf
Permite enviar al medio estándar de salida la información contenida en variables o el resultado obtenido por una expresión, de acuerdo con lo establecido en lo que se conoce como una "cadena de formato". Esta funció toma la representación binaria del valor contenido en la variable (o resultado de la expresión), lo transforma en una cadena de caracteres y finalmente lo coloca en el medio estándar de salida:
Prototipo:
int printf("Cadena de formato", [Lista de variables o expresiones]);
El valor de retorno de la función printf es como sigue: Si la ejecución de printf es correcta se devolverá un valor entero con la cantidad de caracteres que se envió al medio estádar de salida.
Los corchetes [ ] indican que la lista de variables es opcional, por lo tanto la "cadena de formato" es el único argumento obligatorio.
En su forma más simple, printf puede invocarse de la siguiente manera:
printf("Esto es una prueba\n");
Al ejecutar la orden se obtiene en la pantalla (medio estándar de salida):
Como se observa, los caracteres aparecen en la pantalla tal como fueron escritos. El cambio de línea del cursos se debe a la presencia del caracter "\n", de omitirse el cursor se quedaría en la misma línea del mensaje.
También se pueden colocar, dentro de la cadena de formato, caracteres especiales que permitan mostrar el contenido de variables o el resultado de una expresión en diferentes formatos. A estos caracteres se les denomina "Especificadores de Formato".
Los especificadores de formato tienen la siguiente forma:
% [alineación] [ancho] [.precisión] [tamaño] Código_de_Formato
Código de Formato:
El código de formato consiste en un caracter, por lo general una letra, que permite indicarle a la función printf cómo debe interpretar el siguiente valor que mostrará, en el medio estándar de salida. En la taba que se presenta a continuación se puede apreciar la relación de caracteres que se emplean para este fin. La información en esta tabla está basada en el supuesto que no se han colocado caracteres de control, especificadores de ancho, especificadores de precisión o modificadores de tamaño en el especificador de formato.
TIPO DE CARACTER |
VALOR ESPERADO |
FORMATO DE SALIDA |
Para valores numéricos: |
||
d |
Entero |
Entero en base decimal con signo (p.e.: 723, -39, etc.) |
i |
Entero |
Igual que con d |
u |
Entero |
Entero en base decimal sin signo (p.e.: 529, 319, etc.) |
o |
Entero |
Entero en base octal sin signo (p.e.: 456, 714, etc.) |
x |
Entero |
Entero en base hexadecimal sin signo, empleando las letras a,b,c,d,e,f (p.e.: ab7f, 63ce, etc.) |
X |
Entero |
Entero en base hexadecimal sin signo, empleando las letras A,B,C,D,E,F (p.e.: AB7F, 63CE, etc.) |
f |
Punto Flotante |
Valor de punto flotante con signo de la forma [-]d.dddddd (p.e.: 456.498245, -34.714001, etc.) |
e |
Punto Flotante |
Valor de punto flotante con signo en notación científica (p.e.: 4.564982e2) |
E |
Punto Flotante |
Igual que con e, pero con exponente E (p.e.: 4.564982E2, etc.) |
g |
Punto Flotante |
Valor de punto flotante similar al formato e ó f, pero de la forma [-]d.ddd (p.e.: 456.498) |
G |
Punto Flotante |
Igual que con g, pero con E por exponente si el formato e es empleado. |
a |
Punto Flotante |
Valor de punto flotante en formato hexadecimal (p.e.: 0x1.d527f0p+7) |
A |
Punto Flotante |
Igual que con a, pero empleando mayúsculas (p.e.: 0x1.D527F0P+7) |
Para caracteres: |
||
c |
Caracter |
Un caracter simple |
s |
La dirección de una cadena |
Imprime los caracteres desde la dirección dada hasta encontrar un caracter nulo |
% |
Ninguno |
Imprime el caracter % |
Para punteros: |
||
p |
Puntero |
Imprime el la dirección de un puntero |
A continuación se presentan ejemplos que permiten apreciar el efecto de los Códigos de Formato en la función printf :
int a = 65, b = 19290;
float f = 123456.789, h = 234.578;
printf("1) A1 = %d A2 = %c\n", a, a);
printf("2) B1 = %d B2 = %x B3 = %X B4 = %o \n", b, b, b, b);
printf("3) F1 = %f F2 = %e F3 = %E \n", f, f, f);
printf("4) H1 = %a H2 = %A \n", h, h);
Al ejecutar esta porción de código se obtiene en la pantalla el siguiente resultado:
Se puede observar que en la primera línea el especificador de formato %d permite mostrar el contenido de la variable a tal como fue asignado (en base 10), esto es, se aprecia el número decimal 65, mientras que con el especificador de formato %c, para la misma variable, lo que se muestra es el caracter cuyo código ASCII es 65, esto es el caracter A.
En la línea 2), el contenido de la variable b se muestra en cuatro formatos distintos: decimal (%d), hexadecimal empleando letras minúsculas (%x), hexadecimal empleando letras mayúsculas (%X), y por último en formato octal (%o).
La línea 3), muestra el contenido de una variable de punto flotante (f). Como se ve, el primer especificador de formato (%f) hace que se muestre la parte entera del número con la totalidad de sus dígitos y la parte decimal con seis (6) dígitos, como se aprecia, el número no se muestra en su valor exacto, debido a la precisión que se maneja. El especificador de formato %e hace que se muestre el número en notación científica, empleando dos dígitos para el exponente. El especificador de formato %E es igual al anterior pero se emplea la letra E (mayúscula) para separar el exponente.
La línea 4), muestra el contenido de una variable de punto flotante (h). Como se ve, el primer especificador de formato (%a) hace que se muestre el número en notación científica, pero en base hexadecimal. Note que el número empieza con "0x" y que el exponente se indica con una "p". El especificador de formato %A hace que se muestre el número de manera similar pero se emplean la letras mayúsculas.
Especificador de formato [ancho]:
El especificador de ancho es un número entero que fija el tamaño mínimo del campo en que aparecerá el valor de salida. En otras palabras indica el número mínimo de caracteres que se emplearán para mostrar el valor. Los más importantes son:
ANCHO |
EFECTO |
n |
Por lo menos n caracteres serán impresos. Si el valor de salida tiene es menos de n caracteres, se rellena con blancos a la izquierda, si se colocó el caracter de alineación "-" se colocan a la derecha. |
+n |
Igual al anterior pero el resultado siempre empezará con el signo más (+) o menos (-). |
#n |
Si se emplea con los códigos de formato o, x o X se le antepone al valor de salida un 0 (formato octal) o 0x (formato hexadecimal). |
0n |
Por lo menos n caracteres son impresos. Si el valor de salida tiene menos de n caracteres, se llenan con ceros los espacios de la izquierda. |
* |
Coge el siguiente valor de la lista de expresiones y si es un entero lo toma como ancho (n), luego lo aplica al siguiente valor de la lista. |
Especificador de formato [.precisión]:
El especificador de precisión fija el máximo número de caracteres (o mínimo número de dígitos enteros) a imprimir. Los más importantes son:
.PRECISIÓN |
EFECTO |
(nada) |
Si no se coloca, la precisión se fija
por defecto en: |
.0 |
Para los tipos d, i, o, u, x, la precisión se fija por defecto. Para los tipos e, E, f, no se imprime el punto decimal. |
.n |
n caracteres o n espacios decimales son impresos. Si el valor de salida tiene más de n caracteres, la salida se trunca o redondea. |
.* |
Coge el siguiente valor de la lista de expresiones y si es un entero lo toma como precisión (.n), luego lo aplica al siguiente valor de la lista. |
Especificador de formato [alineación]:
El especificador de formato de alineación definen la "justificación" o "alineación" del texto de salida y el signo de numeración. Los más importantes son:.
ALINEACIÓN |
EFECTO |
- |
Justifica a la izquierda el resultado, rellena los espacios a la derecha con blancos. |
(nada) |
Justifica el resultado a la derecha, rellena los espacios a la izquierda con ceros o blancos. |
Los ejemplos que muestran a continuación permiten apreciar el efecto de estos especificadores en la función printf :
// EMPLEANDO VALORES ENTEROS:
int a = 65, b = 1920, c = 7;
int h = 54178;
printf(" 1) %d %d %d\n", a, b, c);
printf(" %d %d %d\n", b, c, a);
printf(" %d %d %d\n\n", c, a, b);
printf(" 2) %7d %7d %7d\n", a, b, c);
printf(" %7d %7d %7d\n", b, c, a);
printf(" %7d %7d %7d\n\n", c, a, b);
printf(" 3) %-7d %-7d %-7d\n", a, b, c);
printf(" %-7d %-7d %-7d\n", b, c, a);
printf(" %-7d %-7d %-7d\n\n", c, a, b);
printf("4) %07d %07d %07d\n", a, b, c);
printf(" %07d %07d %07d\n", b, c, a);
printf(" %07d %07d %07d\n\n", c, a, b);
Al ejecutar el código anterior se obtiene en la pantalla el siguiente resultado:
Se puede observar que en el primer grupo de tres líneas el código de formato dado (%d) hace que los valores aparezcan en forma desordenada, poco agradable y difícil de entender.
En el segundo grupo, se emplea el formato fijándose el ancho en 7 (%7d) esto hacer que los valores aparezcan empleando un mínimo de 7 caracteres, lo que quiere decir que si el número tiene menos de 7 caracteres el resto se rellena con espacios en banco, dándole una mejor apariencia. Los datos se ven perfectamente tabulados y alineados a la derecha.
En el tercer grupo se emplea el especificador de alineación - (%-7d) tiene el mismo efecto que el anterior pero los espacios se colocan a la derecha, por lo que los datos se alinean a la izquierda.
En el último grupo se emplea el especificador de ancho 0n (%07d), como se aprecia los espacios en blanco se reemplazan con ceros.
// EMPLEANDO VALORES ENTEROS CON FORMATOS OCTALES Y HEXADECIMALES:
int h = 54823;
printf(" 1) %10d\n", h);
printf(" 2) %10o\n", h);
printf(" 3) %#10o\n", h);
printf(" 4) %10x\n", h);
printf(" 5) %#10x\n", h);
printf(" 6) %10X\n", h);
printf(" 7) %#10X\n", h);
Al ejecutar el código anterior se obtiene en la pantalla el siguiente resultado:
Se puede observar que en la primera línea el valor de la variable "h" en formato decimal(%10d ).
En las líneas dos y tres, el valor de la variable "h" aparece en formato octal (%10o) pero en el segundo caso se usa el especificador de formato # (%#10o), lo que produce la aparición del cero inicial.
En las líneas cuatro y cinco, el mismo valor de la variable "h" aparece en formato hexadecimal ( %10x) pero en el segundo caso se usa el especificador de formato # (%#10o), lo que produce la aparición de los caracteres 0x inicial. Aquí se puede observar que las letras que corresponden a los valores 10, 11, 12, etc. aparecen en minúsculas.
En las líneas seis y siete, se aprecia lo mismo que en la líneas cuatro y cinco, pero las letra aparecen en mayúsculase.
// EMPLEANDO VALORES DE PUNTO FLOTANTE:
float f = 163201.736;
printf(" 1) [f]= %f [g]= %g [e]= %e [E]= %E\n\n ", f, f, f, f);
printf(" 2) [f0]= %10.0f [g0]= %10.0g [e0]= %10.0e [E0]= %10.0E\n", f, f, f, f);
printf(" 3) [f1]= %10.1f [g1]= %10.1g [e1]= %10.1e [E1]= %10.1E\n", f, f, f, f);
printf(" 4) [f2]= %10.2f [g2]= %10.2g [e2]= %10.2e [E2]= %10.2E\n", f, f, f, f);
printf(" 5) [f3]= %10.3f [g3]= %10.3g [e3]= %10.3e [E3]= %10.3E\n\n", f, f, f, f);
printf(" 6) [a]= %a [A]= %A\n", f, f);
printf(" 7) [a0]= %12.0a [A0]= %12.0A\n", f, f);
printf(" 8) [a1]= %12.1a [A1]= %12.1A\n", f, f);
printf(" 9) [a2]= %12.2a [A2]= %12.2A\n", f, f);
printf("10) [a3]= %12.3a [A3]= %12.3A\n", f, f);
Al ejecutar el código anterior se obtiene en la pantalla el siguiente resultado:
Se puede observar que en la primera línea la diferencia entre los formatos (%f, %g, %e y %f, %E, ).
En el segundo grupo (línas del 2 al 5) se puede observar que los mismos formatos pero ahora empleando diferentes valore del especificador de precisión .n.
En el último grupo (línas del 6 al 10) se puede observar que lo mismo pero empleando el formatos %a y %A. Observe que aquí para el indicador del exponente se uza la letra p o P en lugar de e o E y que los valores aparecen en formato hexadecimal.
// EMPLEANDO EL ESPECIFICADOR DE FORMARTO DE ANCHO * Y EL DE PRECISIÓN .*:
int; t, a = 734;
float g = 234.74;
printf(" 1) %*d\n", 4, a);
printf(" 2) %*d\n", 8, a);
printf(" 3) %*.3f\n", 8, g);
printf(" 4) %*.3f\n\n", 10, g);
printf(" 5) %10.*f\n", 1, g);
printf(" 6) %10.*f\n\n", 3, g);
t = 4; printf(" 7) %*d\n", t, a);
t = 8; printf(" 8) %*d\n", t, a);
printf(" 9) %*.3f\n", t, g);
t = 10; printf("10) %*.3f\n", t, g);
t = 1; printf("11) %10.*f\n", t, g);
t = 3; printf("12) %10.*f\n", t, g);
printf("13) %*.*f\n", 10, t, g);
Al ejecutar el código anterior se obtiene en la pantalla el siguiente resultado:
El asterisco (*) colocado en la cadena de formato, toma el siguiente valor de la lista de expresiones y lo toma como especificador de formato de ancho o de precisión. En ese sentido vemos como en las líneas 1, 2 3 y 4 el asterisco toma el valor 4, 8, 8, y 10 respectivamente como especificador de formato de ancho, y en las líneas 5 y 6 toa los valores 1 y 3 como especificador de formato de precisión.
En las líneas 7 al 12 se aprecia lo mismo pero los valores los toma de las variables.
En la línea 13 se aprecia el uso del asterisco simultáneamente para aespecificar el ancho y l aprecisi>ón.
NOTA: Las especificaciones de formato para las cadenas de caracteres y para los punteros se desarrollarán en los capítulos correspondientes.
FUNCIÓN scanf
Esta función permite leer, uno por uno, los caracteres de un flujo de caracteres que ingresa del medio estándar de entrada. Los caracteres son convertidos de acuerdo a las especificaciones dadas en una cadena de formato y finalmente son asignados o almacenados en las direcciones de memoria que se proporcionan a la función como parámetros de entrada. Estas direcciones pueden estar relacionadas con variables definidas en el programa.
Prototipo:
int scanf("Cadena de formato", Lista de direcciones);
En este caso, a diferencia de la función printf, todos los parámetros son obligatorios.
Una de las características del lenguaje C (no del lenguaje C++) es el hecho que el lenguaje no define parámetros por referencia, esto quiere decir que las funciones no pueden modificar los valores que poseen las variables que se colocan como parámetros. Sin embargo esta propiedad se puede simular, cuando se quiere que una función modifique el valor de una variable que pasa como parámetro, lo que debemos hacer es enviar a la función la dirección de memoria de la variable en lugar de su valor. Esto se puede hacer por medio del operador &, el cual, aplicado a una variable nos entregará precísamente la dirección de memoria de la variable.
En ese sentido, la lista de direcciones es, como su nombre lo indica, un conjunto de direcciones de memoria relacionadas con las variables a las que se desea asignar un valor desde el medio estándar de entrada. Por esto se deberán colocar en esta zona las variables requeridas, anteponiéndoles el operador &.
La "Cadena de formato" trabaja en forma análoga a la cadena empleada en la función printf, en este caso permitirá que, en forma adecuada, se conviertan los caracteres de entrada en el formato esperado por las variables a las que se desea asignar un valor. La "Cadena de formato" estará compuesta por una serie de especificadores de formato, similares a los empleados en la función printf. Debe haber un especificador de formato por cada dirección colocada, de lo contrario se podrá obtener resultados inesperados.
Cuando decimos que la función scanf lee los datos del "flujo de caracteres de entrada", nos estamos refiriendo a que la información que deseamos ingresar al programa se hace mediante un conjunto de caracteres ingresados a través del medio estándar de entrada (que por defecto es el teclado). La función scanf tomará estos caracteres y los procesará según lo que se denomina "campos de entrada". Un campo de entrada es una secuencia de caracteres que termina con un caracter de "fin de campo", "whitespace" (caracter "blanco") o "delimitador de campo". Un caracter "blanco" puede ser espacios en blanco, un tabulador (‘\t’) o un cambio de línea (‘\n’).
La función scanf por lo tanto leerá y transformará caracter por caracter el flujo de entrada, cuando encuentra un "blanco" se detiene, para proceder a asignar el valor convertido (según el formato especificado) en la dirección de memoria indicada en los parámetros. Luego de esto, continua con el siguiente campo. Si al analizar un campo de entrada, los primeros caracteres corresponden a caracteres "blancos", és;tos serán ignorados, procediéndose a trabajar a partir del primer caracter no blanco encontrado.
Durante el proceso de exploración de caracteres, la función scanf podrá modificar el proceso de lectura y almacenamiento del actual campo de entrada si ocurre cualquiera de los siguientes sucesos:
Como se indicó, cuando scanf se detiene por alguna de las razones anteriores, asume que el siguiente carácter no ha sido leído y constituirá el primer caracter del siguiente campo de entrada o el primer caracter en la subsiguiente operación de lectura.
Si en la "cadena de formato", existe una secuencia de caracteres que no es parte de los "especificadores de formato", la secuencia de caracteres en el campo de entrada debe coincidir exactamente con ella. La función scanf leerá los caracteres pero no los asignará. Más adelante, en los ejemplos, se apreciará esta característica.
Especificadores de Formato:
En la "cadena de formato" de la función scanf, los especificadores de formato tienen la siguiente forma:
[*] [ancho] [longitud] Código_de_Formato
Código de Formato:
Al igual que con la función printf el código de formato consiste en un caracter, pero en este caso indicará cómo se deberá transformar el campo de entrada que se está analizando. La información en esta tabla está basada en el supuesto que no se han colocado en los códigos de formato caracteres opcionales, especificadores o modificadores:
TIPO DE CARACTER |
DATO DE ENTRADA ESPERADO |
TIPO DE ARGUMENTO |
NUMÉRICOS: |
||
d |
Entero decimal |
Dirección de un int |
u |
Entero decimal sin signo |
Dirección de un unsigned int |
i |
Entero decimal, octal (p.e.: 0437) o hexadecimal (p.e.: 0xAF23B) |
Dirección de un int |
o |
Entero octal (p.e.: 0437) |
Dirección de un int |
x |
Entero hexadecimal (p.e.: 0xAF23B) |
Dirección de un int |
f, e, g |
Punto flotante |
Dirección de un float |
Caracteres: |
s |
Cadena de caracteres |
Puntero a char |
c |
Caracter |
Dirección de un char |
Caracter de supresión de asignación [*]:
El caracter de supresión de asignación es un asterisco (*). Si el asterisco sigue al signo de porcentaje (%) en la cadena de formato, el siguiente campo será leído pero no será asignado a la dirección colocada como parámetro. Se asume que el dato de entrada suprimido será del tipo especificado por el código de formato que sigue al asterisco.
Especificador de ancho [ancho]:
El especificador de ancho controla el máximo número de caracteres que serán leídos. Esto quiere decir que se van a extarte del flujo de entrada como máximo el número de caracteres que se indican como especificador de ancho. Si durante la extracción de los caracteres se topa con un delimitador de campo, la operación de lectura se da por concluída para esa variable aunque no se haya completado la cantidad indicada en el especificador de ancho.
Especificador de longitud [longitud]:
El especificador de longitud, modifica el código de formato, el más empleado es con la letra l, que al colocarse delante de la f (%lf) se emplea para la lectura de valores de tipo double.
Valor de retorno de scanf:
La función scanf devuelve el número de campos de entrada satisfactoriamente leídos, convertidos y almacenados. Si la función scanf intenta leer luego del final de un archivo, se devolverá el valor -1, el cual podrá se manipulado por la constante sibólica EOF definida en la biblioteca cstdio o stdio.h.
A continuación se muestran ejemplos que permiten apreciar y entender la comportamiento de la función scanf :
int a, num;
double r;
printf("Ingrese un valor entero y otro de punto flotante: ");
num = scanf("%d %lf", &a, &r);
printf("Valor retornado por la función scanf es: %d\n", num);
al ejecutarse esa porción de código se apreciará en la pantalla lo siguiente:
Se observar que de no ser por la función printf sólo se vería el cursor. A partir de ese momento se podrá escribir los campos o valores de entrada, separados por espacios en blanco, tabuladores o cambios de línea. Por ejemplo:
al presionar finalmente la tecla ENTER [↵] el valor de 34 se asignará a la variable a y el valor 73.45 a la variable r. La función scanf devolverá el valor 2 como se aprecia a continuación:
El siguiente ejemplo muestra el comportamiento del caracter de supresión de asignación * :
int a = 0, b = 0, c = 0, ;
scanf("%d %*d %d", &a, &b, &c);
printf("A= %d B= %d C= %d \n", a, b, c);
si al ejecutarse esa porción de código se ingresa:
se imprimirá en la pantalla lo siguiente:
observe que el valor 56 fue leído pero no asignado, simplemente se descartó, luego la función scanf continua con la lectura de los datos, en ese sentido esplora el valor 78 y lo asigna a la variable b, y finalmente el siguiente valor (91) es asignado a la la variable c. La función scanf devuelve 3 ya que leyó y convirtió 4 valores pero sólo asignó 3.
En los siguientes ejemplos se aprecian algunos errores de lectura y la respuesta de la función scanf:
int a=1, b=1, c=1, d=1;
d = scanf("%d %d %d", &a, &b, &c);
printf("A= %d B= %d C= %d D= %d\n", a, b, c, d);
si al ejecutarse se se ingresa:
se imprimirá en la pantalla lo siguiente:
observe que la lectura se truncó al llegar al punto (.), debido a que el valor esperado es un entero (%d). Los caracteres 4 y 5 son convertidos y asignados a la segunda variable, de allí que al imprimir se vea que el valor de la variable es 45. Se considera por lo tanto que se leyeron dos valores válores, por eso es que a d se le asigna el valor de 2.
De la misma manera, si al ejecutarse se se ingresa:
se imprimirá:
el mismo caso anterior, la lectura se truncó al llegar al caracter A.
A continuación se muestra cómo se emplean los especificadores de ancho [ancho]:
int a, b, c;
scanf("%2d%3d%5d", &a, &b, &c);
printf("A= %d B= %d C= %d\n", a, b, c);
si al ejecutarse se se ingresa:
se imprimirá en la pantalla lo siguiente:
los especificadores de ancho indican cuántos caracteres se tomarán del flujo de entrada, por eso los dos primeros caracteres se convierten y asignan a la variable a, los siguientes tres a la variable b y los siguientes cinco a la variable c, el resto se queda en el flujo para una siguiente operación de lectura.
El ejemplo siguiente nos muestra que se puede colocar un texto o patrón en la Cadena de Formato, su efecto, como se podrá observar es un poco peculiar:
int a=1, b=1, c=1;
c = scanf("W78yV61: %d %d", &a, &b);
printf("A= %d B= %d C= %d\n", a, b, c);
Si al ejecutarse se se ingresa:
se imprimirá en la pantalla lo siguiente:
como se aprecia no se asignaron valores a las variables. Para que la asignación se se realice, los caracteres iniciales del flujo de texto deberán coincidir con el texto colocado en la Cadena de Formato. Así, si al ejecutarse se se ingresa:
se imprimirá en la pantalla lo siguiente:
esta propiedad es muy útil, ya que puede servir extrae información que se encuentra en el flujo de entrada dentro de un patrón que no necesariamente corresponda a un tipo de dato estándar. El siguiente ejemplo muestra cómo se puede leer una fecha y una hora, sin tener que procesar una cadena de caracteres manualmente:
int dd, mm, dd; // Variables para manejar una fecha.
int h, m, s; // Variables para manejar una hora.
printf("Ingrese una fecha: ");
scanf("%d/%d/%d", &dd, &mm, &aa);
printf("Ingrese una hora: ");
scanf("%d:%d:%d", &h, &m, &s);
printf("\nLa fecha leída es: %02d-%02d-%4d\n", dd, mm, aa);
printf("La hora leída es:\nHora = %d\nMinutos = %d\nSegundos = %4d\n", h, m, s);
Observe los formatos dados a las funciones scanf, el usuario tendrá que ingresar la fecha y la hora como normalmente se maneja una fecha y una hora, esto es: 5/7/1958 y 8:35:40. Sin embargo el programa, de manera automática, tomará los datos sin tener que hacer una conversión manual de los datos.
En la ejecución se observar:
(Los valores en rojo son la información ingresada por el usuario).
ENTRADA Y SALIDA DE CARACTERES
La entrada y salida de caracteres se maneja en el lenguaje C mediante dos funciones básicas;: "getchar" y "putchar".
FUNCIÓN getchar
Prototipo:int getchar (void);
Características:
Esta función toma el siguiente carácter del buffer de entrada y lo entrega en el formato de un entero de tipo int. No se hace distición en cuanto al caracter que se extrae como la hace scanf, esto es que en esta función no se saltan los espacios, tabuladores o cambios de línea, si están en de buffer los toma de entrada y los entrega.
Una vez leído el carácter, su representación binaria es asignada sin alterar al formato de un entero de tipo int. Por ejemplo, si en el buffer de entrada se encuentra el caracter 'A', cuyo código ASCII es 65, y por lo tanto su representación binaria es 1000 0001, la función getchar() lo entregará en el formato de un int (en este caso en 4 bytes), esto es: 0000 0000 0000 0000 0000 0000 1000 0001. Observe que la representación binaria del caractere no se altera; si luego este resultado es asignado a una variable con un formato más pequeño, como una de tipo char, el caracter queda inalterado.
Si la función getchar() intenta leer luego del final de un archivo, se devolverá el valor -1, el cual podrá se manipulado por la constante sibólica EOF definida en la biblioteca cstdio o stdio.h.
En el siguiente ejemplo se leer´n varios caracteres, aquí se apreciará qué es lo que se asignará a las variables:
char a, b, c, d, e, f;
a = getchar();
b = getchar();
c = getchar();
d = getchar();
e = getchar();
f = getchar();
Si al ejecutar esta porción de código ingresamos:
Luego las variables recibirán los siguientes valores:
Si por otro lado ingresamos:
Las variables recibirán los siguientes valores:
FUNCIÓN putchar
Prototipo:int putchar (int);
Características:
Esta función toma el número contenido en la variable de tipo int, extrae de allí el byte menos significativo y lo envía al medio estándar de salida en el formato de un caracter. La función devuelve el valor del entero ingresado como parámetro el número entero -1 si se produce un error.
Ejemplo:
Dado el siguiente código:
char a = 'H', b = 'O', c = 'L', d = 'A', e = '\n';
int x = 15141;
putchar(a);
putchar(b);
putchar(c);
putchar(d);
putchar(e);
putchar(x);
Se obtiene el siguiente efecto:
Observe que al ejecutar putchar con la variable x, que contiene el valor 15141 se imprime el caracter %. Esto se debe a que la representación binara de 15141 es 0000 0000 0000 0000 0011 1011 0010 0101, cuando se envía este valor a la funció solo se toma el byte menos significativo, en este caso 0010 0101 que corresponde al valor 37 decimal y que a su vez es el código ASCII del caracter %.
FUNCIÓN ungetc
Prototipo:int ungetc (int, FILE*);
Características:
Esta función devuelve al buffer de entrada el caracter ingresado como dato, si se ingresa un dato de tipo int el caractere que se envía correspondde al byte menos significativo. El segundo argumento corresponde a una variable de archivo, si se coloca el valor stdin se trabaja con la entrada estándar, de lo contrario con la variable de archivo relacionada.
En el siguiente capítulo se tratará el ingreso y salida de datos desde el punto de vista del C++, así como el redireccionamiento de la entrada y salida.
![]() |
![]() ![]() |