Entra y Salida en C++

Anuncio
Programación Orientada a Objetos
7 – Entrada/salida en C++
-1-
7 – Entrada y salida en C++
Introducción............................................................................................................................................................1
Streams....................................................................................................................................................................2
La biblioteca iostream.............................................................................................................................................3
Flujos predefinidos ..............................................................................................................................................3
Estructura de la biblioteca iostream ...................................................................................................................4
Operadores de inserción y de extracción ...............................................................................................................5
El operador de inserción <<...............................................................................................................................5
Funciones de salida de ostream: put y write .......................................................................................................6
El operador de extracción >>.............................................................................................................................7
Función get ..........................................................................................................................................................8
Función getline ..................................................................................................................................................10
Función ignore...................................................................................................................................................10
Función read......................................................................................................................................................11
Función putback ................................................................................................................................................12
Función peek......................................................................................................................................................12
Entrada/salida con formato..................................................................................................................................14
Clase ios.............................................................................................................................................................14
Ajustar la anchura de los campos: width ......................................................................................................14
Precisión: precision.......................................................................................................................................15
Relleno: fill ....................................................................................................................................................16
Indicadores de formato..................................................................................................................................18
Manipuladores...................................................................................................................................................22
Ejercicios resueltos ...............................................................................................................................................24
Introducción
Todos los programadores que llegan al C++ desde C están acostumbrados a utilizar las instrucciones de
entrada/salida definidas en el archivo cabecera stdio.h (printf, fprintf, fputs, puts, fwrite...). Esta biblioteca
también está presente en C++, pero no parece ser la adecuada en un lenguaje como C++ en el que los nuevos
tipos tienen un comportamiento completamente equivalente al de los tipos de datos estándar.
El mecanismo de clases de C++ permite crear un sistema consistente y ampliable para los mecanismos de
entrada/salida. Este sistema se conoce como biblioteca de flujos1. Estas clases sirven como mecanismo para
manejar los tipos básicos, pero, además, se puede modificar ampliándolas para incorporar los tipos de datos
definidos por el usuario, como ya se vio en capítulos anteriores cuando se trató la sobrecarga de los flujos de
entrada/salida en C++.
La eficiencia de las funciones de la biblioteca de C++ es otro punto a su favor, sobretodo si se las compara con
las de la biblioteca C:
ƒ El tipo del objeto es conocido en C++ de forma estática por el compilador, en lugar de tener que
comprobar de forma dinámica los campos % como sucedía en C.
ƒ Con C++ se tiene más rapidez. Por ejemplo printf utilizada en C, es básicamente un intérprete de un
pequeño lenguaje constituido principalmente por campos %.
1
Flujo es la traducción de stream.
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
ƒ
ƒ
ƒ
-2-
C++ ofrece un mecanismo extensible para los nuevos tipos de datos definidos por el usuario. En
lenguaje C sería caótico si todo el mundo se pusiera a añadir de forma simultánea nuevos campos %
incompatibles. En C++ los tipos definidos por el usuario (clases) se parecen y actúan como los tipos
básicos.
El sistema de entrada/salida de C++ es un sistema de clases. Esto significa que un usuario puede definir
“algo nuevo” que parezca y se comporte como streams.
Las sentencias de entrada/salida en C++ tienen mayor legibilidad que las de C.
Streams
El concepto de stream o flujo no es nuevo en C++. ANSI C utiliza este concepto para indicar un tipo de puerto
abstracto a través del cual datos no estructurados pueden caminar de forma unidireccional o bidireccional2. Los
flujos en ANSI C se consideran una construcción de entrada/salida de bajo nivel.
Por su parte C++ fue diseñado para el manejo de clases, así los flujos de C++ se encuentran definidos mediante
una jerarquía de clases completa que se distribuye con el compilador. Las versiones antiguas3 de C++ se
distribuían con una jerarquía de clases de streams que actualmente es obsoleta. Las versiones C++ de AT&T
desde la versión 2.0 utilizan la nueva biblioteca iostream.
C++ da a los streams un significado más abstracto. Un programa C++ visualiza entrada o salida como un flujo
de datos. En la entrada un programa extrae bytes de un flujo de entrada, y en la salida un programa inserta bytes
en un flujo de salida. Así, un flujo se puede considerar como una secuencia lineal de bytes con un significado.
Los bytes pueden formar una representación binaria de datos carácter o numéricos. Los bytes de entrada pueden
venir del teclado, pero también pueden proceder de otro dispositivo de almacenamiento como un disco duro u
otro programa. Y de forma análoga los bytes del flujo de salida pueden ir destinados a la pantalla, a una
impresora, a un fichero, o a otro programa. Este enfoque permite que un programa C++ trate la entrada de un
teclado de igual forma que se trata la entrada desde un fichero. El programa C++ examina simplemente el flujo
de bytes, sin necesidad de conocer cuál es la procedencia de los mismos. Esto mismo ocurre en la salida, y ésta
se podrá procesar de forma independiente del lugar a donde vayan destinados los datos.
La gestión de entrada implica dos etapas:
ƒ Asociación de un flujo con una entrada a un programa.
ƒ Conexión del flujo a un archivo.
Esto quiere decir que los flujos necesitan para funcionar dos conexiones, una en cada extremo.
De modo similar la gestión de la salida implica:
ƒ La conexión de un flujo de salida al programa.
ƒ Asociar algún destino de salida con el flujo.
2
3
Los streams constituyen un concepto muy familiar para todos los programadores de C bajo UNIX.
Hasta la versión 1.2.
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
-3-
Si los datos se transfieren sin modificarse entre un extremo y otro, la operación de entrada/salida se denomina
binaria o sin formato.
Si por el contrario los datos, que son una representación interna de la máquina (por ejemplo long), se modifican
en la transferencia entre ambos extremos, y son una representación de caracteres de texto (por ejemplo ASCII),
la operación de entrada/salida se denomina entrada/salida con formato.
La biblioteca iostream soporta ambas operaciones y permite que el programador controle operaciones
específicas de formato mediante el uso de lo que en C++ se conoce como manipuladores.
La biblioteca iostream emplea para las operaciones de entrada/salida buffers. Recordar que un buffer es un
bloque de memoria que se emplea como almacenamiento temporal o intermedio para la transferencia de
información de un dispositivo a un programa o viceversa. Típicamente dispositivos como unidades de disco
transfieren información en bloques de 512 bytes, 1 Kbyte, o incluso mayores.
La biblioteca iostream
La biblioteca iostream es la biblioteca de entrada/salida estándar en C++. El acceso a esta biblioteca se realiza
mediante el archivo cabecera iostream.h4, que se ha venido utilizando de forma reiterada en todos los ejemplos
que se han visto hasta el momento. El sistema de entrada/salida en C++, está definido para trabajar con
diferentes dispositivos (al igual que ocurre en ANSI C). Cada dispositivo se convierte en un dispositivo lógico y se
denomina flujo o stream. Los flujos forman el interfaz común entre el programa, el dispositivo y el usuario. A
este sistema de entrada/salida se le conoce como sistema de archivos a través de buffers. La estructura de los
archivos puede variar con los distintos dispositivos, pero los flujos se comportan siempre de la misma forma5.
Flujos predefinidos
Los siguientes flujos u objetos6 se abren de forma automática cuando se ejecuta un programa C++ y se ha
incluido el fichero de cabecera iostream.h.
Nombre del
flujo
cin
cout
cerr
clog
Tipo de flujo
Flujo de entrada estándar
Flujo de salida estándar
Flujo de salida de error estándar no almacenado en el buffer.
Se emplea para visualizar mensajes de error
Flujo de error estándar a través del buffer. Este flujo es más
adecuado para grandes cantidades de mensajes de error
Clase a la que
pertenece
istream
ostream
ostream
ostream
Flujos predefinidos en C++
4
Las versiones antiguas de la biblioteca de flujos utilizan el fichero cabecera stream.h. En aquellas versiones donde existan
ambos archivos stream.h define el conjunto completo de facilidades, mientras que iostream.h define un subconjunto que es
compatible con las bibliotecas de flujo antiguas. Las versiones modernas de C++ soportan sólo iostream.h.
5
En C y C++ los archivos son considerados como simples flujos de bytes.
6
Ya que un stream no es más que un objeto que hace de puente entre el resto de los objetos de una aplicación y el
dispositivo en el que van a ser almacenados.
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
-4-
Estos flujos se asocian a la consola por defecto, pero pueden ser redirigidos a otros archivos o dispositivos.
Estos cuatro flujos se abren de forma automática antes de que la función main se ejecute, y se cierran justo
después que la función main ha terminado. Por lo tanto no es preciso preocuparse de abrir o cerrar estos flujos.
cerr presenta una ventaja sobre clog, y es que los buffers de salida se limpian cada vez que se utiliza cerr, de
modo que la salida está disponible de forma inmediata en el dispositivo externo, que por defecto es la pantalla.
Estructura de la biblioteca iostream
La biblioteca iostream es francamente potente, está formada por unas 250 funciones y por aproximadamente 20
clases. Esta biblioteca está compuesta por varios archivos cabecera debido a su gran tamaño. Los archivos
cabecera de iostream son:
Nombre archivo
cabecera
iostream.h
Contenido / uso
fstream.h
ƒ
ƒ
ƒ
ƒ
ƒ
strstream.h
iomanip.h
ƒ
ƒ
stdiostream.h
ƒ
Información básica requerida para todas las operaciones de entrada/salida de flujo.
Contiene los objetos cin, cout, cerr y clog.
Proporciona capacidades de entrada/salida con o sin formato.
Contiene los manipuladores más comunes.
Contiene la información necesaria para las operaciones de procesamiento de archivos
controladas por el usuario.
Contiene la información necesaria para realizar operaciones con cadenas.
Contiene la información necesaria para realizar entrada/salida formateada con los
manipuladores de flujo, o para crear unos propios y adecuar el formato de
entrada/salida a unas necesidades particulares.
Rara vez se utiliza éste archivo de cabecera cuando se están creando nuevos
programas C++. Se suele emplear cuando se mejora un programa ya escrito en C con
código escrito en C++.
Archivos de cabecera de iostream
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
-5-
Operadores de inserción y de extracción
La entrada y salida en C++ se realiza mediante los operadores de inserción7 <<, y de extracción8 >>. Una
característica muy importante del sistema de entrada/salida de C++ es que estos operadores se pueden
sobrecargar de forma que se puedan insertar y extraer cualquier tipo de objetos en el flujo.
El operador de inserción <<
El operador << se denomina operador inserción en lugar de operador de desplazamiento a izquierda. El operador
de inserción está sobrecargado para reconocer todos los tipos básicos de C++:
unsigned char
unsigned short
long
double
signed char
int
unsigned long
long double
short
unsigned int
float
La lista no incluye al tipo char, ya que este tipo es sinónimo de unsigned char o de signed char, dependiendo
del compilador.
La clase ostream proporciona una definición de la función operator << para cada uno de los tipos anteriores. El
operador de inserción es un operador binario que retorna una referencia a un objeto ostream.
Un ejemplo del uso del operador inserción es:
void Ejemplo (int edad, char *nombre) {
cout << "Mi nombre es: " << nombre << " y tengo "
<< edad << "años.\n";
}
Del ejemplo se puede deducir que el operador de inserción se puede encadenar. Como es natural el operador de
inserción no realiza un salto de línea, esto hay que hacerlo de forma explícita, bien al estilo C mediante la
secuencia de escape \n, bien al estilo C++ con el manipulador endl.
La sentencia cout que aparece en la función Ejemplo se escribiría de la siguiente forma si se quisiera emplear el
manipulador endl.
cout << "Mi nombre es: " << nombre << " y tengo "
<< edad << "años." << endl;
El manipulador endl tiene una ventaja sobre la secuencia de escape \n, ya que además de insertar una nueva
línea en el flujo, también vacía el buffer de salida. Por lo tanto es equivalente a utilizar \n seguido de fflush.
Algunas de las reglas del operador << son:
ƒ La función operator << devuelve una referencia a un objeto ostream, así que el operador se puede
encadenar
ƒ El operador << está sobrecargado con lo cual se puede utilizar con todos los tipos básicos
ƒ Se debe sobrecargar el operador << para que pueda actuar sobre los tipos definidos por el usuario
7
8
Introducir objetos dentro de un flujo se conoce como inserción.
Sacar objetos de un stream se denomina extracción.
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
-6-
Funciones de salida de ostream: put y write
A parte de las diferentes funciones operador de inserción, la clase ostream proporciona el método put para
visualizar caracteres, y el método write para visualizar cadenas.
La función miembro put inserta un carácter en el flujo. Su prototipo es:
ostream & put(char);
Ejemplo:
// Curso Lenguaje C++
// Programa: Ejemplo de la utilización del método put de la clase ostream
// Fichero: PUT.CPP
#include <iostream.h>
void main (void)
{
cout.put('L').put('U').put('I').put('S') << endl;
cout.put(3) << endl;
cout.put(67).put(82).put(85).put(90) << endl;
}
La salida del programa es:
LUIS
♥
CRUZ
Como se puede ver en el ejemplo la función miembro se puede utilizar con caracteres o con enteros, así
cout.put(77); visualizaría una M. También es posible concatenar varias llamadas como sucedía con el operador
<<, e incluso combinar en la misma sentencia el método put con el operador inserción.
Por su parte el método write se utiliza para insertar una secuencia de caracteres en el flujo. Tiene dos prototipos:
ostream & write (const signed char *, int);
ostream & write (const unsigned char *, int);
Ejemplo:
// Curso Lenguaje C++
// Programa: Utilización del método write de la clase ostream
// Fichero: WRITE.CPP
#include <iostream.h>
#include <string.h>
void main (void) {
char *c1 = "Hola",
*c2 = "Mundo",
*c3 = "Cruel",
*c4 = "ABCDEFGHIJK";
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
-7-
// Ejemplo de concatenación
cout.write(c1, strlen(c1)).put(32).
write(c2, strlen(c2)).put(32).
write(c3, strlen(c3)).put('\n');
// Saca 25 caracteres
cout.write(c2, 25) << endl;
// Sacará basura, pues la longitud de
// la cadena c2 es menor que 25
// Saca 3 caracteres, es decir la cadena Hol
cout.write(c1, 3) << endl;
}
La salida del programa es:
Hola Mundo Cruel
Mundo
DFD ÿMA #EA vBA Ð
Hol
El operador de extracción >>
El operador >> es denominado operador de extracción, y es el opuesto del operador de inserción <<. Su misión
es leer datos de un flujo de entrada, generalmente cin. Un sencillo ejemplo es el siguiente fragmento de código
que sirve para leer un carácter.
char t;
cin >> t;
El símbolo >> señala la dirección del flujo, y lee los caracteres hasta que encuentra uno que no es parte del tipo
requerido (habitualmente espacios, tabuladores o retorno de carro). Este operador se puede utilizar en cascada.
int a, b, c, d, e;
float n;
cin >> a >> b >> c >> d >> e >> n;
Los resultados de pasar tipos incorrectos en la entrada de datos son imprevisibles. A diferencia de scanf al
operador de extracción no se le debe especificar la dirección de la variable, así la siguiente sentencia será un
error.
cin >> &j;
Algunas de las reglas del operador >> son:
ƒ La función operator >> devuelve una referencia a un objeto istream, así que el operador se puede
encadenar
ƒ El operador >> está sobrecargado con lo cual se puede utilizar con todos los tipos básicos
ƒ Se debe sobrecargar el operador >> para que pueda actuar sobre los tipos definidos por el usuario
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
-8-
Un método general de utilizar cin para introducir caracteres es colocarlo dentro de un bucle while, del cual se
saldrá cuando se alcance el fin de fichero9.
while ( cin >> j )
{
cout << j;
}
El operador de entrada >> al igual que ocurre con scanf tiene un inconveniente que lo hace inadecuado cuando
se trata de leer cadenas con espacios en blanco en su interior, ya que sólo lee una cadena hasta que encuentra la
primera ocurrencia del espacio en blanco. Siempre el carácter nulo que marca el final de las cadenas en C es
añadido al final de la cadena que se lea.
Función get
La clase istream contiene la función miembro get para la introducción de cadenas completas de caracteres,
incluyendo espacios en blanco. Esta función no realiza conversiones, simplemente acepta una cadena de
caracteres, y los sitúa en la variable adecuada. Realmente get es una familia de funciones sobrecargadas, alguno
de los prototipos son:
ƒ
istream & get (char *cad, int longitud, char fin='\n');
donde:
− cad es una variable de cadena de caracteres
− longitud es la longitud máxima de la cadena de entrada
− fin es un carácter específico que produce la terminación de la entrada. Por defecto es \n
Así, esta función aceptará caracteres hasta que se alcance la longitud máxima o se introduzca el carácter
de terminación.
ƒ
ƒ
istream & get (unsigned char &);
istream & get (signed char &);
Los dos últimos prototipos sirven para introducir un carácter.
Ejemplo:
// Curso Lenguaje C++
// Programa: Utilización del método get de la clase istream
// Fichero: GET1.CPP
#include <iostream.h>
void main (void)
{
char cad[12];
cout << "Introduce una cadena: ";
cin.get (cad, 4); // 3 caracteres más el carácter nulo final
cout << "\n--" << cad << "--\n";
}
9
Ctrl-Z en MSDOS, y Ctrl-D en UNIX.
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
-9-
El siguiente es un ejemplo de la ejecución del programa. En negrita las entradas del usuario.
Introduce una cadena: 1234567
--123-El programa anterior leerá cadenas de tres caracteres, o hasta que se dé un retorno de carro, o hasta que se
encuentre un fin de fichero válido. Así, en el ejemplo se introduce la cadena 1234567, y la variable cadena cad
queda cargada sólo con el valor 123.
Esta función puede llegar a ser bastante problemática si no se tiene un poco de cuidado, ya que get deja el
carácter de terminación de la entrada en el buffer, y se toma en la siguiente sentencia de entrada de datos.
Así el siguiente programa no funcionaría como debiera, ya que la segunda cadena nunca se llega a pedir, al
tomarse en esta segunda entrada de datos el carácter de terminación de la primera (el carácter intro). Por ello en
la segunda entrada de datos lo que se asume que se ha tecleado una cadena vacía.
#include <iostream.h>
void main (void)
{
char c1[80];
char c2[4];
cout <<
cin.get
cout <<
cin.get
"Introduce una cadena: ";
(c1, 80);
"Introduce una segunda cadena: ";
(c2, 4);
cout << "\n-" << c1 << "-\n-" << c2 << "-\n";
}
El siguiente es un ejemplo de la ejecución del programa. En negrita las entradas del usuario.
Introduce una cadena: Mi cadena
Introduce una segunda cadena:
-Mi cadena--
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 10 -
Función getline
Esta función miembro de istream opera de forma análoga a la función get, siendo su prototipo:
istream & getline (char *, int, char ='\n');
Su diferencia con la función miembro get es que el carácter de terminación se lee antes de que se añada el
carácter '\0'. En consecuencia esta función elimina el carácter de terminación del buffer de entrada.
Con lo que ahora se puede solucionar el problema que se había planteado antes.
// Curso Lenguaje C++
// Programa: Utilización del método getline de la clase istream
// Fichero: GETLINE.CPP
#include <iostream.h>
void main (void)
{
char c1[80];
char c2[4];
cout << "Introduce una cadena: ";
cin.getline (c1, 80);
cout << "Introduce una segunda cadena: ";
cin.get (c2, 4);
cout << "\n-" << c1 << "-\n-" << c2 << "-\n";
}
El siguiente es un ejemplo de la ejecución del programa. En negrita las entradas del usuario.
Introduce una cadena: abcdefghi
Introduce una segunda cadena: 123456
-abcdefghi-123-
Función ignore
Esta es otra de las funciones miembro de la clase iostream. Su prototipo es:
istream & ignore (int n=1, int delim=EOF);
Su cometido es saltarse n caracteres del stream de entrada, o hasta que encuentre el carácter delim. Así la
sentencia.
cin.ignore (25, '\n');
Lee e ignora los siguientes 25 caracteres o hasta que se produzca el primer salto de línea.
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 11 -
Ejemplo:
// Curso Lenguaje C++
// Programa: Utilización del método ignore de la clase istream
// Fichero: IGNORE.CPP
#include <iostream.h>
const int L=25;
void main (void) {
char cadena[L];
char c;
cout << "Introduce una cadena (getline): ";
cin.getline(cadena, L, '%');
cout << "Cadena = " << cadena << endl;
cin.get(c);
cout << "El siguiente carácter de entrada es: "
<< c << endl << endl;
cin.ignore(L, '\n');
// Se desprecia el resto de la línea
cout << "Introduce una cadena (get): ";
cin.get(cadena, L, '%');
cout << "Cadena = " << cadena << endl;
cin.get(c);
cout << "El siguiente carácter de entrada es: "
<< c << endl;
}
El siguiente es un ejemplo de la ejecución del programa. En negrita las entradas del usuario.
Introduce una cadena (getline): abcdeg%78
Cadena = abcdeg
El siguiente carácter de entrada es: 7
Introduce una cadena (get): 122345%09
Cadena = 122345
El siguiente carácter de entrada es: %
Observar que mientras que getline descarta el carácter límite % en la entrada, get no lo hace.
Función read
Esta función lee un número dado de bytes, almacenándolos en la posición especificada. Sus prototipos son:
istream & read (char *, int);
istream & read (signed char *, int);
istream & read (unsigned char *, int);
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 12 -
Al contrario que get y getline, read no añade ningún carácter a la entrada, por lo que no convierte la entrada a
formato cadena.
El uso más típico de esta función es con archivos binarios.
Función putback
Esta función inserta un carácter de nuevo en la cadena de entrada. Dicho carácter se convierte en el primer
carácter leído por la siguiente sentencia de entrada. Su prototipo es:
istream & putback (char);
Función peek
Esta función devuelve el siguiente carácter de la entrada sin ser extraído de la cadena de entrada. Devuelve EOF
si no hay más caracteres en el flujo. Su prototipo es:
int peek();
Ejemplo:
// Curso Lenguaje C++
// Programa: Ejemplo de la utilización de los métodos putback() y peek()
// Fichero: PP.CPP
#include <iostream.h>
#include <process.h>
void main (void) {
char c, encontrado=0;
// Se busca el carácter $ en la entrada
cout << "Introduzca una cadena: " << endl;
while (cin.get(c)) {
if (c!='$') cout << c; // Si no es lo que buscamos lo mostramos
else {
// Si lo encontramos salimos del bucle
encontrado=1;
break;
}
}
if (encontrado) {
cin.get(c);
cout << "\nEl siguiente carácter de la entrada es " << c <<
}
else {
cout << "Se ha llegado al final de la entrada." << endl;
exit(0);
}
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
endl;
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 13 -
// Comprobamos ahora el comportamiento de putback
// Se busca el carácter $ en la entrada
cout << "Introduzca una segunda cadena: " << endl;
while (cin.get(c)) {
if (c!='$') cout << c; // Si no es lo que buscamos lo mostramos
else {
// Si lo encontramos lo volvemos a insertar
cin.putback(c); // y salimos del bucle
encontrado=1;
break;
}
}
if (encontrado) {
cin.get(c);
cout << "\nEl siguiente carácter de la entrada es " << c <<
}
else {
cout << "Se ha llegado al final de la entrada." << endl;
exit(0);
}
endl;
// Repetimos lo anterior con otra cadena de entrada, pero ahora
// se utiliza peek
cout << "Introduzca una tercera cadena: " << endl;
while (cin.peek() != '$') {
cin.get(c);
cout << c;
}
cin.get(c);
cout << "\nEl siguiente carácter de la entrada es " << c << endl;
}
El siguiente es un ejemplo de la ejecución del programa. En negrita las entradas del usuario.
Introduzca una cadena:
abcdefg$hijk
abcdefg
El siguiente carácter de la entrada es h
Introduzca una segunda cadena:
ijk
123456$7890
123456
El siguiente carácter de la entrada es $
Introduzca una tercera cadena:
7890
RSTUV$WXYZ
RSTUV
El siguiente carácter de la entrada es $
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 14 -
Entrada/salida con formato
En C++ existen dos formas propias de manipular el formato de la salida:
ƒ
ƒ
Emplear las funciones miembro de la clase ios.
Emplear unas funciones especiales que reciben el nombre de manipuladores.
Clase ios
Dentro de esta clase se han definido los métodos para realizar una amplia gama de operaciones de formato con la
salida. Así se tienen funciones para el control de la base, la anchura del campo, carácter de relleno, etc.
Ajustar la anchura de los campos: width
Para llevar a cabo esta acción se tiene la función miembro width. Esta función se ocupa de establecer la anchura
del campo de la variable de estado. Tiene dos prototipos:
int width();
int width(int i);
El primero de ellos se limita a informar del estado actual de la anchura del campo, mientras que el segundo
establece la anchura del campo a i caracteres, y devuelve el valor de la anchura anterior.
Como width es un método tiene que utilizar un objeto, como pueden ser cout y cin.
Cuando se emplea con cin tiene el sentido de limitar el número de caracteres que se van a leer.
Por su parte cuando se utiliza con cout, si el contenido de la variable es menor que la anchura fijada del campo,
se visualizará el contenido de dicha variable justificado a la derecha de un campo de longitud la que se haya
fijado, y el resto del campo se rellenará con espacios. Si por el contrario la longitud del contenido de la variable
es mayor que la longitud del campo, se ignora la configuración de width y se muestra el valor completo de la
variable. Por tanto, nunca se pierde información.
El valor por defecto para la anchura es 0. Esto no significa que no se tenga reservado espacio para la salida de la
variable, sino que se utilice el mínimo número de caracteres necesarios.
Después de cada inserción width se inicia a 0.
Ejemplo:
// Curso Lenguaje C++
// Programa: Ejemplo de la utilización de width
// Fichero: WIDTH.CPP
#include <iostream.h>
void main (void)
{
float mat[] = {0.5561, 0.4, 0.1234567, 1.2, -1.0002};
int sz = sizeof(mat) / sizeof(float);
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 15 -
cout << "Salida Normal sin utilizar width()\n";
for (register int i=0; i<sz; cout << mat[i++] << endl);
cout << "\nSalida utilizando width(4)\n";
for (i=0; i<sz; ){
cout.width(4);
cout << mat[i++] << endl;
}
cout << "\nSalida utilizando width(8)\n";
for (i=0; i<sz; ){
cout.width(8);
cout << mat[i++] << endl;
}
}
La salida del programa anterior es, después de haber sido compilado con Microsoft Visual C++ .NET:
Salida Normal sin utilizar width()
0.5561
0.4
0.123457
1.2
-1.0002
Salida utilizando width(4)
0.5561
0.4
0.123457
1.2
-1.0002
Salida utilizando width(8)
0.5561
0.4
0.123457
1.2
-1.0002
Precisión: precision
Para establecer el número de dígitos de coma flotante después del punto decimal se utiliza la función miembro
precision. Sus prototipos son:
int precision ()
int precision (int)
El primer prototipo se corresponde con una función miembro que retorna el valor de la variable de estado de
precisión. El segundo prototipo representa a la función que fija la precisión a un valor determinado. y devuelve
el estado anterior. El valor por defecto es 0, y significa que los números en coma flotante se representan hasta
con 6 dígitos decimales, y si el número tiene más decimales el último dígito se redondea.
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 16 -
Ejemplo:
// Curso Lenguaje C++
// Programa: Ejemplo de la utilización de precision()
// Fichero: PREC.CPP
#include <iostream.h>
void main (void)
{
double numero = 1.2345678901;
cout << "La precisión por defecto es: "
<< cout.precision() << "\n";
for (register int i=0; i<=10; i++) {
cout.precision(i);
cout << "\tCon precisión ";
cout.width(2);
cout << cout.precision() << "\t\t" << numero << "\n";
}
}
La salida del programa es:
La precisión por defecto es: 0
Con precisión 0
Con precisión 1
Con precisión 2
Con precisión 3
Con precisión 4
Con precisión 5
Con precisión 6
Con precisión 7
Con precisión 8
Con precisión 9
Con precisión 10
1.234568
1.2
1.23
1.235
1.2346
1.23457
1.234568
1.2345679
1.23456789
1.23456789
1.2345678901
Relleno: fill
Las partes no utilizadas del campo de salida son rellenadas por el objeto cout con espacios en blanco. Para
cambiar esta situación por defecto se puede usar la función miembro fill pudiendo fijar un carácter de relleno.
Esta función tiene dos prototipos:
char fill ();
char fill (char);
Como en los casos anteriores, el primer prototipo devuelve el valor de la variable de estado de relleno actual, y
el segundo lo cambia y devuelve el anterior.
Como ejemplo se va a modificar el programa anterior, de forma que cuando se muestre el valor de la precisión
se haga siempre con dos dígitos, y de ser un número de un dígito, se rellene con ceros.
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 17 -
// Curso Lenguaje C++
// Programa: Ejemplo de la utilización de fill
// Fichero: FILL.CPP
#include <iostream.h>
void main (void)
{
double numero = 1.2345678901;
cout << "La precisión por defecto es: "
<< cout.precision() << "\n";
for (register int i=0; i<=10; i++) {
cout.precision(i);
cout << "\tCon precisión ";
cout.width(2);
cout.fill('0');
cout << cout.precision() << "\t\t" << numero << "\n";
}
}
La salida del programa es:
La precisión por defecto es: 0
Con precisión 00
Con precisión 01
Con precisión 02
Con precisión 03
Con precisión 04
Con precisión 05
Con precisión 06
Con precisión 07
Con precisión 08
Con precisión 09
Con precisión 10
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
1.234568
1.2
1.23
1.235
1.2346
1.23457
1.234568
1.2345679
1.23456789
1.23456789
1.2345678901
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 18 -
Indicadores de formato
Cada objeto derivado de ios contiene una variable de estado de indicadores. Estos indicadores o banderas
controlan el formato de entrada y salida. Asociada a cada indicador existe una constante, nombre que representa
una máscara de bits, que se emplea cuando se accede y cambia el indicador de una variable de estado específica.
Indicador ios
ios::skipws
Valor numérico
0x0001
Significado
Saltar sobre espacios en blanco, sólo entrada
(1 - bit 1)
ios::left
0x0002
Justificar a la izquierda
(2 - bit 2)
ios::right
0x0004
Justificar a la derecha
(4 - bit 3)
ios::internal
0x0008
Rellenar números con espacios después de los indicadores de base
(8 - bit 4)
ios::dec
0x0010
Formato en base 10. Conversión decimal
(16 - bit 5)
ios::oct
0x0020
Formato en base 8. Conversión octal
(32 - bit 6)
ios::hex
0x0040
Formato en base 16. Conversión hexadecimal
(64 - bit 7)
ios::showbase
0x0080
Visualizar indicador de base numérica. Sólo salida
(128 - bit 8)
ios::showpoint
0x0100
Visualizar el punto decimal. Salida float
(256 - bit 9)
ios::uppercase
0x0200
Visualizar dígitos hexadecimales en mayúsculas
(512 - bit 10)
ios::showpos
0x0400
Añade un signo + a los números positivos
(1024 - bit 11)
ios:scientific
0x0800
Utilizar notación científica para reales
(2048 - bit 12)
ios::fixed
0x1000
Utilizar notación coma fija para reales
(4096 - bit 13)
ios::unitbuf
0x2000
Limpia los flujos después de la inserción
(8192 - bit 14)
ios::stdio
0x4000
Limpia stdout y stderr después de la inserción
(16384 - bit 15)
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 19 -
Los anteriores indicadores se manejan por medio de las funciones siguientes: setf, unsetf, y flags.
Prototipos de las funciones
Significado
long ios::flags()
Informa de todos
long ios::flags(long flags)
Informa de todos, establece todos
long ios::setf(long flags)
Informa de todos, establece máscara
long ios::setf(long bis, long flags)
Informa de todos, establece un grupo (pone a 0 los
primeros, después pone a 1 los segundos)
long ios::unsetf(long flags)
Informa de todos, limpia la máscara
En la clase ios existen tres constantes que se utilizan como segundo parámetros de setf y sirven para seleccionar
los grupos de indicadores.
Constante
Indicadores seleccionados
ios::adjustifield
Justificación izquierda, derecha e interna
ios::basefield
Indicadores de conversión decimal, octal y hexadecimal
ios::floatfield
Indicadores de notación científica y de coma fija
Ejemplo 1:
// Curso Lenguaje C++
// Programa: Ejemplo de la utilización de indicadores de formato
// Fichero: INDI1.CPP
#include <iostream.h>
void main (void) {
float e1=5.75, e2=6.25, e3=e1+e2;
cout.setf(ios::showpoint);
// Forzamos a que utilice el punto decimal
// aunque la salida no lo necesite
cout.setf(ios::showpos);
// Si el número es positivo que saca un
// signo + delante
cout << e3 << endl;
cout << 3 << endl;
cout << -3.0 << endl;
cout.unsetf(ios::showpoint);
//
//
//
//
//
Salida +12.000000
Salida +3
Salida -3.000000
Desactivamos la salida forzosa del punto
decimal
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
cout << e3 << endl;
cout.unsetf(ios::showpos);
cout << 3 << endl;
- 20 -
// Salida +12
// Desactivamos la salida del +
}
La salida del programa es:
+12.000000
+3
-3.000000
+12
3
Ejemplo 2:
// Curso Lenguaje C++
// Programa: Ejemplo de la utilización de indicadores de formato
// Fichero: INDI2.CPP
#include <iostream.h>
void main (void)
{
cout.setf(ios::showbase);
// Forzamos a que se muestre el
// indicador de base numérica
cout.setf(ios::hex, ios::basefield);
// Formato en hexadecimal
cout << 13 << "\t" << 25 << "\t" << 3 << endl;
cout.setf(ios::oct, ios::basefield);
// Formato en octal
cout << 13 << "\t" << 25 << "\t" << 3 << endl;
cout.setf(ios::dec, ios::basefield);
// Formato en decimal
cout << 13 << "\t" << 25 << "\t" << 3 << endl;
cout.unsetf(ios::showbase);
// Ya no mostramos el indicador
// de base numérica
cout.setf(ios::hex, ios::basefield);
// Formato en hexadecimal
cout << 13 << "\t" << 25 << "\t" << 3 << endl;
cout.setf(ios::oct, ios::basefield);
// Formato en octal
cout << 13 << "\t" << 25 << "\t" << 3 << endl;
cout.setf(ios::dec, ios::basefield);
// Formato en decimal
cout << 13 << "\t" << 25 << "\t" << 3 << endl;
}
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 21 -
La salida del programa es:
0xd
015
13
d
15
13
0x19
031
25
19
31
25
0x3
03
3
3
3
3
Ejemplo 3:
// Curso Lenguaje C++
// Programa: Ejemplo de la utilización de indicadores de formato.
// Fichero: INDI3.CPP
#include <iostream.h>
void main (void) {
double num=1.23455698;
int i=102;
cout << "i= " << i <<
"\tnum= " << num << endl;
// Se guardan los valores originales de los indicadores
long indi=cout.flags();
// Activación de algunos indicadores
cout.setf(ios::hex, ios::basefield);
cout << "i= " << i << "\tnum= " << num << endl;
cout.setf(ios::showbase | ios::uppercase |ios::scientific);
cout << "i= " << i << "\tnum= " << num << endl;
// Se restauran los valores por defecto
cout.flags(indi);
cout << "i= " << i << "\tnum= " << num << endl;
}
La salida del programa es:
i=
i=
i=
i=
102
66
0X66
102
num=
num=
num=
num=
1.23456
1.23456
1.234557E+000
1.23456
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 22 -
Manipuladores
Hasta ahora se han visto varias formas de manejo del formato, bastante potentes, pero un poco engorrosas de
emplear. C++ ofrece un enfoque más amigable con lo que se denominan manipuladores.
Los manipuladores son funciones especiales que se pueden emplear con los operadores de inserción y extracción
para formatear la entrada y la salida.
Los manipuladores que existen se encuentran recogidos en la siguiente tabla:
Manipulador
Entrada/Salida
Significado
dec
E/S
endl
S
Envía carácter de nueva línea
ends
S
Envía un nulo \0
flush
S
Vacía un flujo
Formato de datos numéricos en decimal
hex
E/S
Formato de datos numéricos en hexadecimal
oct
E/S
Formato de datos numéricos en octal
resetiosflags(long lg)
E/S
Desactiva los indicadores de lg
setbase(int i)
S
Formato de los números en la base i
setfill(char c)
E/S
Establece c como carácter de relleno
setiosflags(long lg)
E/S
Activa los indicadores de lg
setprecision(int i)
E/S
Establece i dígitos decimales
setw(int i)
E/S
Establece i caracteres de anchura de campo
ws
E
Ignora los caracteres en blanco iniciales
Los manipuladores dec, hex, oct, ws, endl, ends, y flush se encuentran definidos en iostream.h, el resto lo
están en iomanip.h.
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 23 -
El uso de los manipuladores es muy sencillo. Se va a ver un ejemplo.
Ejemplo:
//
//
//
//
Curso Lenguaje C++
Programa: Ejemplo de la utilización de indicadores de formato
Fichero: MANIP1.CPP
Compilado con Microsoft Visual C++ .NET
#include <iostream.h>
#include <iomanip>
using namespace std;
void main (void)
{
// Justificación de la salida a la derecha
// Establecer la anchura a 50
// Desactivar justificación a la derecha
cout << setiosflags(ios::right) << setw(50)
<< "Esto va a la derecha" << resetiosflags(ios::right) << endl;
cout << "Esto está en la izquierda" << endl;
cout << "Ahora unos numeritos:" << endl;
cout << hex << 10 << setw(5) << oct << 10 << setw(5)
<< dec << 10 << endl;
cout << setfill('#') << hex << 16 << setw(5) << oct << 16
<< setw(5) << dec << 16 << setfill(' ') << endl;
}
La salida de este programa es:
Esto va a la derecha
Esto está en la izquierda
Ahora unos numeritos:
a
12
10
10###20###16
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Programación Orientada a Objetos
7 – Entrada/salida en C++
- 24 -
Ejercicios resueltos
1. Crear un pequeño programa en el cual dependiendo de una variable de control, los mensajes salgan por la
salida estándar (cout), o por la salida de error (cerr), pero empleando para ello la misma sentencia.
// Curso Lenguaje C++
// Programa: Cambio en la dirección de la salida
// Fichero: EJER7-1.CPP
#include <iostream.h>
void main (void)
{
ostream *s;
int bandera=0;
if (bandera)
s=&cout;
else
s=&cerr;
*s << "Hola" << endl;
}
Ingeniería Técnica en Informática de Sistemas (3er curso)
Departamento de Informática y Automática – Universidad de Salamanca
© Francisco José García Peñalvo y Juan Andrés Hernández Simón
(v1.05 – Feb.2005)
Descargar