05. Funciones de entrada/salida
Objetivos
- Entender el concepto de entrada y salida.
- Conocer los métodos para leer datos de la entrada.
- Conocer los métodos para escribir datos a la salida.
Introducción
Los programas informáticos básicamente son manipuladores de información, ya sea un programa de contabilidad, un sistema de inteligencia artificial o el sistema operativo de un ordenador. Por tanto, los programas necesitan poder obtener esta información para procesarla y poder dar salida a los resultados. Si no tenemos entrada, los programas se limitarían a hacer siempre lo mismo con los mismos datos y, si no tenemos salida, los resultados del programa nunca se podrían usar para nada.
Cuando pensamos en entrada de datos nos referimos a cualquier tipo de entrada; pueden ser las teclas que se pulsan en un teclado, la posición del ratón o pantalla táctil, un fichero en disco, una dirección de internet, un lector de códigos de barras, una webcam o el micrófono. Del mismo modo, cuando hablamos de salida nos podemos referir a un amplio abanico de opciones, desde la pantalla del ordenador, un archivo, una impresora o el sistema de control de un robot.
Entre todos estos dispositivos hay dos que tienen un papel especialmente relevante: el teclado para la entrada de datos y la pantalla para la salida de datos. De hecho, si no se cambia explícitamente, la entrada estándar (o stdin del inglés standard input) es el teclado, y la salida estándar (o stdout del inglés standard output) es la pantalla.
En esta guía veremos cómo podemos comunicarnos con estos dispositivos para leer información desde el teclado y mostrarla en la pantalla.
1. Entrada
Lo primero que hay que saber es que cuando se pulsan teclas en un teclado, estas se convierten en su código ASCII y se almacenan como caracteres en lo que se llama un buffer, el cual contiene toda la secuencia de caracteres que han escrito y que ningún programa ha leído todavía.
Los métodos para leer datos irán leyendo de este buffer considerando qué tipo de información intentamos leer. Hay que tener en cuenta que el salto de línea también cuenta como una tecla cualquiera y se representa habitualmente con '\n'. Este buffer es una estructura conocida como FIFO (First In First Out), lo que quiere decir que lo leeremos en orden de llegada. A continuación se muestra un ejemplo del contenido del buffer a medida que se van pulsando teclas del teclado:
Tecla pulsada | Contenido del buffer |
---|---|
1 | '1' |
3 | '3' '1' |
2 | '2' '3' '1' |
Salto de línea | '\n' '2' '3' '1' |
a | 'a' '\n' '2' '3' '1' |
Salto de línea | '\n' 'a' '\n' '2' '3' '1' |
Para leer la información de este buffer, tenemos a nuestra disposición un conjunto de instrucciones en lenguaje algorítmico según el tipo de datos que queremos leer:
Instrucción | Descripción |
---|---|
readChar | Lee un carácter del buffer |
readBoolean | Lee un boolean del buffer |
readInteger | Lee un entero del buffer |
readReal | Lee un real del buffer |
readString | Lee un real del buffer |
Veamos cuál sería el resultado de aplicar estas instrucciones teniendo en cuenta que c es una variable de tipo carácter, i una variable de tipo entero y r una de tipo real:
Buffer Inicial | Instrucciones | Buffer final | Resultado |
---|---|---|---|
'\n' 'a' '\n' '2' '3' '1' | c:= readChar() | '\n' 'a' '\n' '2' '3' | La variable c contiene el valor 49 (valor ASCII del carácter 1). |
'\n' 'a' '\n' '2' '3' '1' | i:= readInteger() | '\n' 'a' | La variable i contiene el valor 132. Dado que los enteros pueden tener varias cifras, se lee hasta el salto de línea o un espacio. |
'\n' 'a' '\n' '2' '3' '1' | r:= readReal() | '\n' 'a' | La variable r contiene el valor 132,0. Dado que los reales pueden tener varias cifras, se lee hasta el salto de línea o un espacio. |
'\n' 'a' | c:= readChar() | '\n' | La variable c contiene el valor 97 (valor ASCII del carácter a). |
'\n' 'a' | i:= readInteger() | Error. No se puede interpretar la letra a como un entero. | |
'\n' 'a' | r:= readReal() | Error. No se puede interpretar la letra a como un real. |
2. Salida
En el caso de la salida pasa algo similar. Cuando escribimos en la salida estándar, toda la información queda guardada en forma de caracteres en un buffer, que se va leyendo y mostrando en la pantalla.
Para escribir la información en este buffer y se muestre, tenemos a nuestra disposición una serie de instrucciones en lenguaje algorítmico según el tipo de datos que queremos escribir:
Instrucción | Descripción |
---|---|
writeChar | Escribe un carácter en el buffer |
writeBoolean | Escribe un boolean en el buffer |
writeInteger | Escribe un entero en el buffer |
writeReal | Escribe un real en el buffer |
writeReal | Escribe una cadena de carácteres en el buffer |
3. Entrada y salida en C
Para poder acceder a la entrada y salida estándares en C, necesitaremos utilizar una librería estándar de C. Las librerías son conjuntos de funcionalidades que extienden las instrucciones básicas del lenguaje C, facilitando hacer ciertas tareas. En este caso la librería se llama stdio (standard input/output) y, para poder utilizarla, tendremos que importarla a nuestro programa. Para ello, tendremos que añadir la siguiente línea de código al principio de nuestro archivo (sin punto y coma):
Una vez importada, podemos utilizar sus funcionalidades directamente. Tanto en el caso de la entrada como en el de la salida, hay que especificar el tipo y formato de los datos. Para ello, se pasa la cadena de formato de entrada y salida, donde las variables que se quieren leer o escribir se indican con el símbolo % y, a continuación, una letra especificando el tipo de variable. A continuación se muestra un resumen de las más habituales:
Tipo de dato | Especificativo de tipo | Ejemplo de datos |
---|---|---|
Carácter | %c | 'a' |
Boolean | %u | 0 (equivalente de true), 1 (equivalente de false); en general, cualquier tipo enumerativo usará el especificativo %u. |
Entero | %d | 34 o -32 |
Real | %f | 3.1415 |
String | %s | "Hello World" |
Puntero | %p | 0x000000AA; los punteros los trataremos en el módulo "13. Punteros en C". |
A continuación veremos ejemplos de estas cadenas de formato para la entrada y la salida.
3.1. Entrada
El método genérico para la entrada de datos es el método scanf, que espera una cadena de formato indicando qué debe leer del buffer de teclado y la lista de variables donde se guardarán los valores leídos. Todas las variables deben ir precedidas del símbolo & (que significa «dirección de» y que veremos en la unidad de memoria). En la siguiente tabla tenemos la traducción de los métodos en lenguaje algorítmico anteriores, teniendo en cuenta que c es una variable de tipo carácter, i de tipo entero y r de tipo real:
Método | Traducción a C |
---|---|
readChar | scanf("%c", &c) |
readBoolean | scanf("%u", &b) |
readInteger | scanf("%d", &i) |
readReal | scanf("%f", &r) |
readString | scanf("%s", s) |
Además, en el caso de leer un carácter tenemos la instrucción getchar que nos permite hacer una asignación directa:
3.2. Salida
En el caso de la salida por pantalla, tenemos el método printf, que espera una cadena de formato indicando qué tiene que escribir y la lista de variables de donde obtener la información. En la siguiente tabla tenemos la traducción de los métodos en lenguaje algorítmico anteriores, teniendo en cuenta que c es una variable de tipo carácter, i de tipo entero y r de tipo real:
Método | Traducción a C |
---|---|
writeChar | printf("%c", c) |
writeBoolean | printf("%u", b) |
writeInteger | printf("%d", i) |
writeReal | printf("%f", r) |
writeString | printf("cadena de carácteres") |
writeString | printf("%s", s) |
Además, cabe recordar que tenemos un carácter especial para indicar el salto de línea ('\n'), que lo podemos utilizar en el formato para indicar que queremos que se haga un salto de línea. De lo contrario todo se escribirá seguido en la misma línea.
Adicionalmente, podemos añadir modificaciones a cómo queremos que se muestren los datos. Estos modificadores se ponen entre el símbolo % y el especificativo de tipo:
%[modificadores][ancho][.precisión]especificativo
A continuación vemos unos cuantos ejemplos. Podéis encontrar más información, aquí.
Formato | Valor variable | Salida |
---|---|---|
"%0d" | 3 | 3 |
"%03d" | 003 | |
"%f" | 3.14 | 3.14000 |
"%2.1f" | 3.14 | 3.1 |
4. Ejemplos
4.1. Ejemplo 05_01: entrada
Enunciado:
Definid un algoritmo que lea dos enteros y calcule su suma. Haced su traducción a C.
Solución:
algorithm sum
var
a: integer;
b: integer;
s: integer;
end var
a:= readInteger();
b:= readInteger();
s:= a + b;
end algorithm
int main() {
int a;
int b;
int s;
scanf("%d", &a);
scanf("%d", &b);
s=a+b;
return 0;
}
4.2. Ejemplo 05_02: salida
Enunciado:
Definid un algoritmo que, dadas dos variables a = 2 y b = 2, escriba por pantalla el mensaje: "La suma de a y b es 4". Haced su traducción a C.
Solución:
algorithm sumaSalida
var
a: integer;
b: integer;
end var
a:= 2;
b:= 2;
writeString("La suma d'a i b és :");
writeInteger(a + b);
end algorithm
int main() {
int a=2;
int b=2;
printf("La suma d'a i b és : %d", a + b);
return 0;
}
4.3. Ejemplo 05_03: entrada y salida
Enunciado:
Definid un algoritmo que requiera tres enteros y muestre por pantalla el valor medio de los tres. Haced su traducción a C.
Solución:
algorithm sumaEntradaSalida
var
a: integer;
b: integer;
c: integer;
m: float;
end var
a:= readInteger();
b:= readInteger();
c:= readInteger();
m=(a+b+c)/3.0;
writeReal(m);
end algorithm
int main() {
int a;
int b;
int c;
float m;
scanf("%d", &a);
scanf("%d", &b);
scanf("%d", &c);
m=(a+b+c)/3.0;
printf("%f", m);
return 0;
}
Resumen
En esta guía hemos visto la utilización de los métodos scanf y printf para leer y escribir datos en los dispositivos estándar de entrada y salida. También hemos visto que se puede modificar el formato de los datos.