Está en la página 1de 24

INGRESO Y SALIDA DE DATOS DESDE EL LENGUAJE C

Cuando 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
ser 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".
El Lenguaje C define una serie de funciones externas al núcleo de C, estas funciones
se agrupan, de acuerdo a la labor que realizan, en “bibliotecas de funciones”. Estas
bibliotecas de funciones proporcionadas por el compilador se incorporan a un
programa mediante la instrucción de pre procesador: #include.
Este es el caso de las funciones que permiten el ingreso y la salida de datos en un
programa que se agrupan en la biblioteca estándar stdio (standard input output) que
se encuentra en el archivo stdio.h. Por esta razón, en todo programa en lenguaje C al
que se le ingresen datos o que se muestren resultados se debe colocar la siguiente
cláusula de preprocesador:
#include <stdio.h>.
A continuación mostraremos las funciones para realizar esta labor:

Función printf
Permite enviar al medio estándar de salida la información contenida en las variables o
los resultados obtenidos por expresiones, de acuerdo con lo establecido en lo que se
conoce como una "cadena de formato". Esta función 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.
La forma cómo se manipula esta función se muestra a continuación:
int printf("Cadena de formato", [Lista de variables o expresiones]);
La función printf devuelve o retorna un valor entero con la cantidad de caracteres que
se envió al medio estándar 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):

1/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
Como se observa, los caracteres aparecen en la pantalla tal como fueron escritos. El
cambio de línea del cursor 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.
Caracter Valor 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.)
Entero en base hexadecimal sin signo, empleando las
x Entero
letras a, b, c, d, e, f (p. e.: ab7f, 63ce, etc.)
Entero en base hexadecimal sin signo, empleando las
X Entero
letras A, B, C, D, E, F (p. e.: AB7F, 63CE, etc.)
Valor de punto flotante con signo de la forma
f Punto flotante
[-] d.dddddd (p. e.: 456.498245, -34.714001, etc.)
Igual a f pero esta forma se debe emplear con los
lf Punto flotante
tipos de dato double.
Valor de punto flotante con signo en notación
e Punto flotante
científica (p. e.: 4.564982e2)
Igual que con e, pero con exponente E (p. e.:
E Punto flotante
4.564982E2, etc.)
Valor de punto flotante similar al formato e o f, pero
g Punto flotante
de la forma [-] d.ddd (p. e.: 456.498)
Igual que con g, pero con E por exponente si el
G Punto flotante
formato e es empleado.
Valor de punto flotante en formato hexadecimal (p. e.:
a Punto flotante
0x1.d527f0p+7)
Igual que con a, pero empleando mayúsculas (p. e.:
A Punto flotante
0x1.D527F0P+7)
Para caracteres:
2/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.

c Caracter Un caracter simple


La dirección de Imprime los caracteres desde la dirección dada hasta
s
una cadena encontrar un caracter nulo
% Ninguno Imprime el caracter %
Para punteros:
p Puntero Imprime 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]:

3/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
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
Por lo menos n caracteres serán impresos. Si el valor de salida tiene
n menos de n caracteres, se rellena con blancos a la izquierda, si se colocó
el caracter de alineación "-" se colocan a la derecha.
Igual al anterior pero el resultado siempre empezará con el signo más (+)
+n
o menos (-).
Si se emplea con los códigos de formato o, x o X se le antepone al valor
#n
de salida un 0 (formato octal) o 0x (formato hexadecimal).
Por lo menos n caracteres son impresos. Si el valor de salida tiene menos
0n
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
Si no se coloca, la precisión se fija por defecto en:
1 para los tipos d, i, o, u, x, X
6 para los tipos e, E, f, lf
Todos los dígitos significativos para los tipos g, G
Imprime todos los caracteres hasta el primer caracter nulo para el tipo s
No afecta al tipo c.
.0 Para los tipos d, i, o, u, x, la precisión se fija por defecto. Para los tipos e, E,
f, lf 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 define 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.
Si no se coloca, justifica el resultado a la derecha, rellena los espacios a la
izquierda con ceros o blancos.
Los ejemplos que se 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);
4/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
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 hace
que los valores aparezcan en 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:

5/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.

Se puede ver 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 las líneas cuatro y cinco, pero las
letras aparecen en mayúsculas.
// 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:

6/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.

Se puede observar que en la primera línea la diferencia entre los formatos (%f, %g,
%e y %f y %E).
En el segundo grupo (líneas del 2 al 5) se puede observar los mismos formatos pero
ahora empleando diferentes valores del especificador de precisión .n.
En el último grupo (líneas del 6 al 10) se puede observar lo mismo pero empleando el
formato %a y %A. Observe que aquí para el indicador del exponente se una 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:

7/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.

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 toma
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 son tomados de las variables.
En la línea 13 se aprecia el uso del asterisco simultáneamente para especificar el
ancho y la precisió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.
La forma cómo se manipula esta función se muestra a continuación:
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 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,
cuando se quiere que una función modifique el valor de una variable que pasa como
parámetro, esta propiedad se puede simular. 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á
precisamente 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

8/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
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, caracter blanco (whitespace) o delimitador de campo. Este caracter 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 delimitador 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 un delimitador, estos serán
ignorados, procediéndose a trabajar a partir del primer caracter que no es un
delimitador.
Los especificadores de formato tienen la siguiente forma:
% [*] [ancho] 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:
Caracter Valor de entrada Tipo de argumento
Para valores numéricos:
d Entero en base decimal Dirección de un int
u Entero en decimal sin signo Dirección de un unsigned int
Entero en base decimal, octal o
i Dirección de un int
hexadecimal (p. e.: 287, 0437, 0x11F).
o Entero en base octal (p. e.: 0437) Dirección de un int
Entero en base hexadecimal (p. e.:
x Dirección de un int
0x11F)
f, e, g Punto flotante Dirección de un float

9/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.

lf Punto flotante Dirección de un double


Para caracteres
c Caracter Dirección de un char
s Cadena de caracteres Puntero a 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 extraer 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
concluida para esa variable aunque no se haya completado la cantidad indicada en el
especificador de ancho.

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á ser manipulado por la constante
simbólica EOF definida en la biblioteca stdio.h.
A continuación se muestran ejemplos que permiten apreciar y entender el
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:

10/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
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 34 es leído y asignado a la variable a, valor 56 fue leído pero no


asignado, simplemente se descartó, luego la función scanf continua con la lectura de
los datos, explora el valor 78 y lo asigna a la variable b, y finalmente el siguiente valor
91 es asignado a 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 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, en ese punto se
detiene la ejecución de la función scanf por eso la variable c no cambia su valor inicial
(1) como se ve en la impresión. Se considera por lo tanto que se leyeron dos valores,
por eso es que a la variable d se le asigna el valor de 2.
De la misma manera, si al ejecutar el programa se ingresa:

Se imprimirá:

Es 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;
11/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
scanf("%2d%3d%5d", &a, &b, &c);
printf("A= %d B= %d C= %d\n", a, b, c);
Si al ejecutarse 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 ingresa:

Se imprimirá en la pantalla lo siguiente:

Como se aprecia no se asignaron valores a las variables. Para que la asignación 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 ingresa:

Se imprimirá en la pantalla lo siguiente:

Esta propiedad es muy útil, ya que puede servir para extraer 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, aa; // 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:\n”);
printf(“Hora = %d\nMinutos = %d\nSegundos = %4d\n", h, m, s);

12/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
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 observa:

(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
La forma cómo se manipula esta función se muestra a continuación:
int getchar (void);
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 distinción en cuanto al caracter que se
extrae como la hace scanf, esto se debe a que en esta función no se saltan los
espacios, tabuladores o cambios de línea, si están en el buffer los toman de la 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 caracter no se altera; si luego este resultado es asignado a
una variable con un formato más pequeño, como uno 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á ser manipulado por la constante simbólica EOF definida en la
biblioteca stdio.h.
En el siguiente ejemplo se leerán varios caracteres, aquí se apreciará qué es lo que se
asignará a las variables:
13/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
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
La forma cómo se manipula esta función se muestra a continuación:
int putchar (int);
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 o 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);
14/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira 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ón
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 %.

Redireccionamiento de la entrada y salida de datos

Esta es una propiedad del sistema operativo, y se aplica sobre cualquier programa
ejecutable (programas con extensión .exe). Esto quiere decir que no depende ni del
lenguaje de programación ni del entorno de desarrollo que estemos empleando.
Por lo general, el ingreso de datos se realiza a través del teclado y la salida a través
de la pantalla del computador, pues bien, esta propiedad hará que, como su nombre lo
indica, se pueda direccionar la entrada a otro medio, por ejemplo un archivo de textos,
o el medio de salida, por ejemplo otro archivo de textos o la impresora.
Para realizar esta forma de ejecutar un programa primero debe ubicar el programa
ejecutable, para esto debemos seguir los pasos indicados en la “Guía de creación,
ejecución y depuración de un programa en C/C++”. Como se ve en la guía, para ejecutar
el programa solo debemos colocar el nombre del programa en la línea de comandos y al
presionar la tecla ENTER [↵] el programa se ejecutará, si el programa requiere que se
le ingresen datos, estos serán ingresados por medio del teclado, y los resultados se
verán impresos en la pantalla. A continuación mostramos este proceso:

Al presionar la tecla ENTER [↵] el programa nos pedirá los valores como se indica a
continuación:

15/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.

Luego de ingresar los valores:

Se mostrarán los resultados:

Como se ha visto, se ha ingresado la base y altura por medio del teclado y el resultado
salió impreso en la pantalla.
Ahora redireccionaremos primero la entrada de datos, de modo que los datos sean
tomados desde un archivo de textos. Para esto sitúese en el explorador de archivos en
la carpeta que contiene el programa ejecutable, como se muestra a continuación:

Allí presione el botón derecho del mouse, se desplegará un menú y allí seleccione la
opción “Nuevo” como se ve a continuación:

16/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.

En el nuevo menú que se despliega como se muestra y allí seleccione la opción


“Documento de texto”:

Esto creará un archivo de textos en la carpeta donde está su archivo ejecutable como
se ve a continuación:

Cámbiele el nombre, por ejemplo póngale “Datos”:

Luego abra el archivo, y allí coloque los datos para la base y altura del triángulo, los
datos deben estar en el mismo orden en que ingresó los datos desde la entrada
estándar, como se ve a continuación:

17/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.

Base del triángulo

Altura del triángulo

Guarde los cambios y luego cierre el archivo.


Luego diríjase nuevamente a la ventana donde se ejecuta el programa, coloque el
nombre del programa ejecutable y luego agregue el redireccionamiento como se
muestra a continuación:

Como ve, luego del nombre del programa debe colocar el signo < (menor que) seguido
del nombre del archivo de textos con los datos. El signo < debe tomarlo como si fuera
una flecha que indica la dirección del flujo de datos (programa  datos) esto le indica
al sistema operativo que los datos ingresarán a través del archivo de textos en lugar
del teclado. Al presionar la tecla ENTER [↵], el programa se ejecutará y mostrará lo
siguiente:

Lo que primero debe fijarse es que, aunque la salida es un poco peculiar, la respuesta
final del programa muestra el valor del área del triángulo de manera correcta para los
datos colocados en el archivo.
La particularidad de lo mostrado se debe a que para el programa es transparente la
forma cómo se ingresan los datos, simplemente ejecutará el programa de la misma
manera sea cual fuera el medio de entrada.
Recordemos el código del programa que estamos ejecutando:

Cuando se ejecute la línea 22 (printf…) el programa envía al medio de salida, la


pantalla del computador, el mensaje para que se ingrese la base del triángulo.
Recuerde que se ha redireccionado la entrada, no la salida. Fíjese que la instrucción no
envía el cambio de línea (‘\n’). Luego, se ejecuta la línea 23 (scanf…), en donde se
18/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
ingresará el valor para la base, aquí el valor se toma del archivo, por lo que el
programa no se detiene e inmediatamente se ejecutan las líneas 25 y 26, de la misma
manera que las dos anteriores por lo que en la salida los mensajes se ven uno a
continuación del otro. Finalmente se calcula el área y se muestra los resultados, por
eso es que los resultados salen uno a continuación del otro.
Se recomienda que cuando se planee que un programa será ejecutado cambiando el
medio de entrada, no se coloquen mensajes pidiendo los datos, para que sólo se vea el
resultado final.
Ahora redireccionaremos la salida, para esto coloque en la línea de comandos lo
siguiente:

En este caso se usará el caracter > (mayor que) seguido del nombre de un archivo, que
también debe ser interpretado como una flecha que indica el flujo de los datos
(programa  resultados), esto le indica al sistema operativo que los resultados se
enviarán al archivo cuyo nombre colocamos en la línea de comandos. Debe tener
cuidado que no exista un archivo con ese nombre en la carpeta donde está su programa
ejecutable porque cuando se corra el programa, el archivo será borrado y reemplazado
por uno nuevo con los datos impresos por el programa.
Al presionar la tecla ENTER se ejecutará el programa y se verá lo siguiente:

Solamente el cursor (_) pasó a la siguiente línea, esto se debe a que al redireccionar la
salida de datos todo lo que se imprima será enviado al archivo de textos, por eso no
vemos el mensaje con el pedido de ingreso de la base, tampoco veremos el mensaje con
el pedido de ingreso de la altura, sin embargo en estos instantes el programa se ha
detenido en la línea 23 (scanf…) esperando que usted ingrese el valor para la base.
Entonces ingrese la base y luego la altura como se muestra a continuación:

Luego de escribir la altura usted verá lo siguiente:

19/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
No se ve el resultado porque se envió al archivo reporte.txt. Para verificar esto,
diríjase a la carpeta donde está el programa ejecutable y observe que ha aparecido el
archivo en la carpeta, como se ve en la figura siguiente:

Al abrirlo verá lo siguiente:

Como ve, el resultado es similar al que apareció en la anterior ejecución del programa
pero con la diferencia que esta información está almacenada en un archivo de texto.
Finalmente redireccionaremos simultáneamente ambos medios, entonces, coloque en la
línea de comandos lo siguiente:

El presionar la tecla ENTER verá lo siguiente:

El programa se ejecutó tomando los datos desde el archivo “Datos.txt” y enviando los
resultados al archivo “reporte2.txt” por eso es que parece que no se ejecutó el
programa, pero si va nuevamente al explorador de archivos verá que se creó el nuevo
archivo, como se ve a continuación:

Al abrirlo podrá apreciar lo siguiente:

20/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
El redireccionamiento de los medios de datos es una buena forma de probar los
programas que normalmente se ejecutarán desde los medios de entrada y salida
estándar, esto para que no tengamos que escribir los datos cada vez que se prueba el
programa y para tener un registro de las ejecuciones del programa para poder
compararlas.
Está forma de ejecutar un programa es muy práctica, sin embargo solo permite que los
datos se ingresen por un único archivo y la salida también se envía a un único archivo.
Si se necesitan leer los datos desde varios archivos o los resultados se deben enviar a
varios archivos de texto este método no funciona. Por lo tanto debemos estudiar otra
forma de escribir nuestros programas y esto se realizará empleando funciones que
están adaptadas para este fin. A continuación revisaremos estas funciones.

Manejo de archivos de texto en el Lenguaje C

Un archivo de textos es una colección de caracteres almacenados en la memoria


secundaria del computador. La idea de emplear archivos de textos es poder almacenar
información que podrá ser empleada cada vez que se ejecute el programa o por
diferentes programas, esto significa que podemos almacenar en un archivo de textos
los datos que vamos a introducir al programa y hacer que el programa los tome de allí
sin necesidad que los tengamos que digitar cada vez que queremos ejecutar el
programa. La ventaja de emplear archivos de textos es que la consola del computador
ha sido diseñada de manera similar a la de un archivo de textos, de modo que
introducir datos a un programa desde la consola o desde un archivo de textos es casi
lo mismo, las instrucciones que utilizaremos en uno u otro caso serán muy parecidas.
Un archivo de textos se puede crear mediante instrucciones de programa, pero la
forma más fácil de hacerlo es empleando un procesador de palabras simple como el
“Block de notas” que proporciona el sistema operativo Windows.
Variable de archivo
Para poder utilizar un archivo de textos se requiere relacionar de manera lógica el
archivo con el programa, la manera de hacerlo es definiendo una variable especial en el
programa denominada variable de archivo la cual será conectada al mismo archivo.
La forma cómo se define una variable de archivo en lenguaje C es la siguiente:
FILE *nombre_de_variable;
Donde la palabra “FILE” (en mayúsculas) es un tipo de dato definido en la biblioteca
stdio.h y que permite definir la variable, la cual debe ser declarada obligatoriamente
como un puntero.
A continuación se presentan ejemplos:
FILE *archivo, *achAlumnos, *fileDatos;
Asignación de un archivo a una variable de archivo y apertura del archivo
Una vez definida la variable de archivo, hay que asignarle la información necesaria
para que la variable se conecte con el archivo físico, esta operación se realiza
mediante la función denominada fopen, cuya función es asignar información adecuada a
la variable de archivo para que pueda manipular el archivo físico y la de “abrir” el
21/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
archivo para que se pueda empezar a trabajar con él. A continuación se describe cómo
se maneja esta función:
variable_de_archivo = fopen (nombre_del _archivo, modo de apertura);
Donde el nombre del archivo, como su nombre lo indica, debe corresponder a una
cadena de caracteres con el nombre del archivo que queremos crear o de donde
queremos obtener los datos.
El modo de apertura también es una cadena de caracteres en ella se indica la forma en
que se abrirá el archivo y qué operación vamos a realizar en el archivo. A continuación
se muestra qué información debe contener esta cadena:
Modo de apertura Operación
Permite abrir un archivo de modo que se puedan realizar sólo

“r”
operaciones de lectura a partir del inicio del archivo. El archivo debe
existir de lo contrario se producirá un error y se interrumpirá la
ejecución del programa.
Permite abrir un archivo de modo que se puedan realizar sólo
“w” operaciones de escritura a partir del inicio del archivo. Si el archivo no
existe lo crea, de lo contrario borra el contenido del archivo.
Permite abrir un archivo de modo que se puedan realizar sólo
operaciones de escritura a partir del final del archivo, en otras
“a” palabras nos permite agregar información a un archivo. El archivo debe
existir, de lo contrario se produce un error y se interrumpirá la
ejecución del programa.
Existen otros modos de apertura pero serán expuestos más adelante.
Ejemplos de cómo se emplea esta función se describe a continuación:
File *archAlumnos, *reporteDeNotas, *archHistorico;

archAlumnos = fopen(“alumnos.txt”, “r”);


reporteDeNotas = fopen(“Notas 2018.txt”, “w”);
archHistorico = fopen(“midDoc\\Notas historicas.txt”, “a”);

Observe que el nombre del archivo debe incluir la extensión del archivo (.txt),
también vea que el nombre del archivo puede contener la ruta donde se encuentra el
archivo, como se ve en el tercer ejemplo, allí debe tener mucho cuidado cuando separa
una carpeta de otra, el sistema operativo obliga a poner el carácter ‘\’, sin embargo
como en el lenguaje C este es un carácter especial (carácter de control) debemos
colocar dos juntos, esto es \\.
Finalmente debe tener sumo cuidado en colocar el modo de apertura entre comillas
dobles (“r”) y no entre comillas simples (‘r‘).
Verificación correcta de la apertura de un archivo
Una de las cosas que debemos hacer cuando abrimos un archivo es verificar que se
abrió correctamente. De no hacerlo, el programa no funcionará correctamente
terminando por interrumpirse abruptamente. Lo crítico de esto es que la interrupción
del programa no se va a producir en la línea donde se usa la función fopen si no en
cualquier otra línea del programa, haciendo muy difícil depurar el programa.
Por esta razón estamos obligados a verificar explícitamente la correcta apertura del
archivo a fin de poder detectar un posible error y corregirlo.

22/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
Afortunadamente la forma de verificación es muy simple, si el sistema no puede abrir
el archivo, la función fopen devolverá el valor NULL que será asignado a la variable de
archivo. Por lo tanto la verificación debe consistir en lo siguiente:
File *archAlumnos, *reporteDeNotas, *archHistorico;

archAlumnos = fopen(“alumnos.txt”, “r”);


if (archAlumnos == NULL) {
printf(“1| archivo alumnos.txt”);
return 1;
}
reporteDeNotas = fopen (“Notas 2018.txt”, “w”);
if (reporteDeNotas == NULL) {
printf(“ERROR en la apertura del archivo Notas 2018.txt”);
return 1;
}

Observe que la verificación debe hacerse inmediatamente después de la apertura. El


uso de la orden “return” hará que el programa se interrumpa, entienda que esta
interrupción debe hacerse porque si no se abrió bien el archivo no se puede continuar
con la ejecución del programa.
Cierre de un archivo
Inmediatamente se termine de realizar operaciones con un archivo, éste debe
cerrarse. De no hacerse se podría perder información importante del archivo. La
razón de esto es que cuando se realizan operaciones de entrada o salida de un archivo,
la operación no desplaza la información directamente desde el archivo hacia las
variables o viceversa, lo que sucede es que en el momento de abrir el archivo para leer
de él, parte de la información contenida en el archivo pasa a un espacio temporal de
memoria denominado ‘buffer’. Cuando se hace una operación de lectura se toman los
datos del buffer y no del archivo, cuando toda la información del buffer se ha leído,
nuevamente se le carga otra parte del archivo y el proceso continúa. Cuando se
escribe en un archivo, la información se envía al buffer, cuando el buffer se llena, se
descarga la información que contiene al archivo. Si el programa se interrumpiera
abruptamente antes de cerrar el archivo, el contenido del buffer no pasaría al
archivo, y por lo tanto se perdería la información que contiene. Esto es un suceso
crítico en operaciones de escritura.
El esquema siguiente muestra este proceso:
variables disco
buffer
Operaciones de escritura

Memoria principal

variables buffer disco

Operaciones de lectura

Memoria principal

Esta forma de manejar los datos se da para evitar demasiadas operaciones


directamente sobre el disco, de no hacerlo así se perdería mucho tiempo en el proceso
23/24
Curso: Técnicas de programación [INF144] J. Miguel Guanira E.
ya que el disco es un dispositivo mucho más lento que la memoria principal del
computador, por otro lado se evita un desgaste innecesario del disco. Luego de cerrar
un archivo, se puede volver a abrir empleando nuevamente la función fopen. Para
cerrar un archivo se emplea la función fclose, cuya sintaxis se muestra a continuación.
fclose (variable_de_archivo);
Entrada y Salida de datos desde archivos de texto
Una vez abierto el archivo, se podrán realizar operaciones de escritura o de lectura,
según como fue abierto, y estas operaciones se tornan muy sencillas ya que para
hacerlo se emplean funciones muy similares a las que se emplean con la entrada
estándar (printf y scanf). Estas funciones sólo tienen una variante, se debe colocar
como primer parámetro la variable de archivo relacionada al archivo con el que
queremos trabajar, el resto de la sintaxis, así como la forma como trabaja es idéntico
a la forma como se trabaja desde la entrada estándar.
int fprintf(variable_de_archivo, “Cadena de formato", [Lista de variables o expresiones]);
int fscanf (variable_de_archivo, "Cadena de formato", Lista de direcciones);
int fgetc (variable_de_archivo);
int fputc (int, variable_de_archivo);
Observe que las funciones para el manejo de caracteres difieren en nombre con
respecto a las que se emplean en el medio estándar.
Devolución de caracteres al buffer de entrada
Es posible devolver los caracteres al buffer de entrada, esto quiere decir que una vez
leído el carácter se puede regresar al buffer para poder leerlo nuevamente. La
función que lo permite es la siguiente:
int ungetc (int, variable_de_archivo);
Esta función, como se indicó, devuelve al buffer de entrada el caracter ingresado
como dato, si se ingresa un dato de tipo int el caracter que se envía corresponde 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.

24/24

También podría gustarte