Falta incluir imágenes, añadir colores,
completar el contenido... incluso releer ;-)
4. Entrada/salida básica
Vamos a ver con algo más de detalle las órdenes
habituales de entrada y salida estándar: printf y scanf, que ya
conocemos, putchar y getchar, que aun no habíamos visto. Todas
ellas se encuentran definidas en <stdio.h>
4.1. printf
Ya conocemos el manejo básico de la orden “printf”:
printf( formato [, dato1, dato2, ...])
(el corchete indica que la cadena de texto de formato debe existir
siempre, pero los datos adicionales son opcionales, pueden no aparecer).
Esta orden muestra un texto formateado en pantalla. Para usarla es
necesario incluir <stdio.h> al principio de nuestro programa.
Hemos visto cómo emplearla para mostrar número enteros,
números reales y caracteres. Ahora vamos a ver más
detalles sobre qué podemos mostrar y cómo hacerlo:
Los “especificadores de formato” que podemos usar son:
c Un único carácter
d Un número entero decimal (en base 10) con signo
f Un número real (coma flotante)
e Un número real en notación exponencial, usando la “e” en minúscula
E Un número real en notación exponencial, usando la “E” en minúscula
G Usa “e” o “f” (el más corto), con “e” minúscula
G Usa “e” o “f” (el más corto), con “E” mayúscula
i Un número entero decimal con signo
u Un número entero decimal sin signo (unsigned)
h Corto (para un entero)
l Largo (para un entero)
x Un número entero decimal sin signo en hexadecimal (base 16)
X Un número entero decimal sin signo en hexadecimal en mayúsculas
o Un número entero decimal sin signo en octal (base 8)
s Una cadena de texto (que veremos en el próximo tema)
Si usamos %% se mostrará el símbolo de porcentaje en pantalla.
Queda alguna otra posibilidad que todavía es demasiado avanzada
para nosotros, y que comentaremos mucho más adelante, cuando
hablemos de “punteros”.
Además, las órdenes de formato pueden tener
modificadores, que se sitúan entre el % y la letra
identificativa del código.
Si el modificador es un número, especifica
la anchura mínima en la que se escribe ese argumento (por
ejemplo: %5d).
Si ese número empieza por 0, los espacios
sobrantes (si los hay) de la anchura mínima se rellenan con 0
(por ejemplo: %07d).
Si ese número tiene decimales, indica el
número de dígitos totales y decimales si los que se va a
escribir es un número (por ejemplo %5.2f), o la anchura
mínima y máxima si se trata de una cadena de caracteres
(como %10.10s).
Si el número es negativo, la salida se
justificará a la izquierda, dejando espacios en blanco al final
(en caso contrario, si no se dice nada, se justifica a la derecha,
dejando los espacios al principio).
Vamos a ver un ejemplo de todo esto:
/*---------------------------*/
/* Ejemplo en C nº 36: */
/* C036.C */
/*
*/
/* Detalles de "printf" */
/*---------------------------*/
#include <stdio.h>
int entero = 1234;
int enteroNeg = -1234;
float real = 234.567;
char letra = 'E';
int contador;
main()
{
printf("El número entero vale %d en notación decimal,\n", entero);
printf(" y %o en notación octal,\n", entero);
printf(" y %x en notación hexadecimal,\n", entero);
printf(" y %X en notación hexadecimal en mayúsculas,\n", entero);
printf(" y %ld si le hacemos que crea que es entero largo,\n", entero);
printf(" y %10d si obligamos a una cierta anchura,\n", entero);
printf(" y %-10d si ajustamos a la izquierda.\n", entero);
printf("El entero negativo vale %d\n", enteroNeg);
printf(" y podemos hacer que crea que es positivo: %u (incorrecto).\n",
enteroNeg);
printf("El número real vale %f en notación normal\n", real);
printf(" y %5.2f si limitamos a dos decimales,\n", real);
printf(" y %e en notación científica (exponencial).\n", real);
printf("La letra es %c y un texto es %s.\n", letra, "Hola");
printf(" Podemos poner \"tanto por ciento\": 50%%.\n");
}
El resultado de este programa sería:
El número entero vale 1234 en notación decimal,
y 2322 en notación octal,
y 4d2 en notación hexadecimal,
y 4D2 en notación hexadecimal en mayúsculas,
y 1234 si le hacemos que crea que es entero largo,
y 1234 si obligamos a una cierta anchura,
y 1234 si ajustamos a la izquierda.
El entero negativo vale -1234
y podemos hacer que crea que es positivo: 4294966062 (incorrecto).
El número real vale 234.567001 en notación normal
y 234.57 si limitamos a dos decimales,
y 2.345670e+002 en notación científica (exponencial).
La letra es E y el texto Hola.
Podemos poner "tanto por ciento": 50%.
Casi todo el fácil de seguir, pero aun así hay vemos alguna cosa desconcertante...
Por ejemplo, ¿por qué el número real aparece como
234.567001, si nosotros lo hemos definido como 234.567? Hay que
recordar que los números reales se almacenan con una cierta
pérdida de precisión. En un “float”
sól se unos garantiza que unas 6 cifras sean correctas. Si
mostramos el número con más de 6 cifras (estamos usando
9), puede que el resultado no sea totalmente correcto. Si esta
pérdida de precisión es demasiado grande para el uso que
queramos darle, deberemos usar otro tipo de datos, como double.
Lo de que el número negativo quede mal cuando lo intentamos
escribir como positivo, también nos suena conocido: si el primer
bit puesto en un número con signo es uno, indica que es un
número negativo, mientras que en un número positivo el
primer bit es la cifra binaria más grande (lo que se conoce como
“el bit más significativo”). Por eso, tanto el
número -1234 como el 4294966062 se traducen en la misma
secuencia de ceros y unos, que la sentencia "printf" interpreta de una
forma u otra según le digamos que el número el positivo o
negativo.
Como curiosidad, ese número 4294966062 sería un valor
distinto (64302) si usáramos un compilador de 16 bits en vez de
uno de 32, porque sería una secuencia de 16 ceros y unos, en vez
de una secuencia de 32 ceros y unos.
Otra opción más avanzada es que si usamos un asterisco
(*) para indicar la anchura o la precisión, los primeros datos
de la lista serán los valores que se tomen para indicar la
anchura y la precisión real que se usarán:
int minimo = 5;
int máximo = 10;
printf("%*.*s", minimo, maximo, "mensaje");
4.2. scanf
Como ya sabemos, el uso de “scanf” recuerda mucho al de
“printf”, salvo porque hay que añadir el
símbolo & antes de los nombres de las variables en las que
queremos almacenar los datos. Aun así, los códigos de
formato no son exactamente los mismos. Vamos a ver los más
importantes:
c Un único carácter
d Un número entero decimal (base 10) con signo
D Un entero largo en base 10 con signo
f Un número real (coma flotante)
e,E Un número real en notación exponencial
g,G Permite “e” o “f”
i Un número entero con signo
I Un número entero largo con signo
u Un número entero decimal sin signo (unsigned)
U Un número entero decimal largo sin signo (unsigned)
H Corto (para un entero)
L Largo (para un entero)
X Un número entero sin signo en hexadecimal (base 16)
X Un número entero largo sin signo en hexadecimal en mayúsculas
O Un número entero sin signo en octal (base 8)
O Un número entero largo sin signo en octal (base 8)
S Una cadena de texto (que veremos en el próximo tema)
Como vemos, la diferencia más importante es que si en vez de un
entero queremos un entero largo, se suele usar el mismo carácter
escrito en mayúsculas.
Al igual que en “printf”, se puede indicar un número
antes del identificador, que nos serviría para indicar la
cantidad máxima de caracteres a leer. Por ejemplo,
“scanf("%10s", &texto)” nos permitiría leer un
texto de un tamaño máximo de 10 letras.
Aun así, “scanf” a veces da resultados
desconcertantes, por lo que no es la orden más adecuada cuando
se pretende crear un entorno amigable. Más adelante veremos
formas alternativas de leer del teclado.
4.3. putchar
Es una forma sencilla de escribir un único carácter en la pantalla:
putchar('A');
o si usamos una variable:
putchar(x);
4.4. getchar
Lee el siguiente carácter que esté disponible en el
buffer del teclado (una memoria intermedia que almacena todas las
pulsaciones de teclas que hagamos):
letra = getchar();
Si no quedaran más letras por leer, el valor que nos
daría es EOF, una constante predefinida que nos indicará
el final de un fichero (End Of File) o, en este caso, de la entrada
disponible por teclado. Se usaría así:
letra = getchar();
if (letra==EOF) printf("No hay más letras");
Vamos a ver un ejemplo del uso de getchar y de putchar:
/*---------------------------*/
/* Ejemplo en C nº 37: */
/* C037.C */
/*
*/
/* getchar y putchar */
/*---------------------------*/
#include <stdio.h>
char letra1, letra2;
main()
{
printf("Introduce dos letras y pulsa Intro: ");
letra1 = getchar();
letra2 = getchar();
printf("Has tecleado: ");
putchar(letra1);
printf(" y también %c", letra2);
}
Vemos que aunque “getchar” lea tecla a tecla, no se analiza
lo que hemos tecleado hasta que se pulsa Intro. Si tecleamos varias
letras, la primera vez que usemos getchar nos dirá cual era la
primera, la siguiente vez que usemos getchar nos dirá la segunda
letra y así sucesivamente.
En este ejemplo sólo leemos dos letras. Si se teclean tres o
más, las últimas se pierden. Si se teclea una letra y se
pulsa Intro, “letra1” será la letra tecleada...
¡y “letra2” será el Intro (el carácter
‘\n’ de avance de línea)!
Estos problemas también los tenemos si intentamos leer letra a
letra con “scanf("%c", ...” así que para hacer esto
de forma fiable necesitaremos otras órdenes, que no son
estándar en C sino que dependerán de nuestro compilador y
nuestro sistema operativo, y que veremos más adelante.