7 – Entrada y salida en C++mrodriguez/E_SProgAvanz.pdf · Operadores de inserción y de...

24
Programación Orientada a Objetos 7 – Entrada/salida en C++ - 1 - Ingeniería Técnica en Informática de Sistemas (3 er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón 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 flujos 1 . 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.

Transcript of 7 – Entrada y salida en C++mrodriguez/E_SProgAvanz.pdf · Operadores de inserción y de...

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 1 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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.

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 2 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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 Los streams constituyen un concepto muy familiar para todos los programadores de C bajo UNIX. 3 Hasta la versión 1.2.

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 3 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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

Tipo de flujo Clase a la que pertenece

cin Flujo de entrada estándar istream cout Flujo de salida estándar ostream cerr Flujo de salida de error estándar no almacenado en el buffer.

Se emplea para visualizar mensajes de error ostream

clog Flujo de error estándar a través del buffer. Este flujo es más adecuado para grandes cantidades de mensajes de error

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.

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 4 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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 Contenido / uso

iostream.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.

fstream.h Contiene la información necesaria para las operaciones de procesamiento de archivos controladas por el usuario.

strstream.h Contiene la información necesaria para realizar operaciones con cadenas. iomanip.h 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.

stdiostream.h 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

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 5 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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 signed char short unsigned short int unsigned int long unsigned long float double long double

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 Introducir objetos dentro de un flujo se conoce como inserción. 8 Sacar objetos de un stream se denomina extracción.

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 6 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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";

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 7 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

// 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

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 8 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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.

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 9 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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 << "Introduce una cadena: "; cin.get (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: Mi cadena Introduce una segunda cadena: -Mi cadena- --

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 10 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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.

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 11 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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);

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 12 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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 << endl; } else { cout << "Se ha llegado al final de la entrada." << endl; exit(0); }

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 13 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

// 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 << endl; } else { cout << "Se ha llegado al final de la entrada." << endl; exit(0); } // 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 $

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 14 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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);

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 15 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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.

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 16 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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 1.234568 Con precisión 1 1.2 Con precisión 2 1.23 Con precisión 3 1.235 Con precisión 4 1.2346 Con precisión 5 1.23457 Con precisión 6 1.234568 Con precisión 7 1.2345679 Con precisión 8 1.23456789 Con precisión 9 1.23456789 Con precisión 10 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.

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 17 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

// 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 1.234568 Con precisión 01 1.2 Con precisión 02 1.23 Con precisión 03 1.235 Con precisión 04 1.2346 Con precisión 05 1.23457 Con precisión 06 1.234568 Con precisión 07 1.2345679 Con precisión 08 1.23456789 Con precisión 09 1.23456789 Con precisión 10 1.2345678901

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 18 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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 Valor numérico Significado

ios::skipws 0x0001

(1 - bit 1) Saltar sobre espacios en blanco, sólo entrada

ios::left 0x0002

(2 - bit 2) Justificar a la izquierda

ios::right 0x0004

(4 - bit 3) Justificar a la derecha

ios::internal 0x0008

(8 - bit 4) Rellenar números con espacios después de los indicadores de base

ios::dec 0x0010

(16 - bit 5) Formato en base 10. Conversión decimal

ios::oct 0x0020

(32 - bit 6) Formato en base 8. Conversión octal

ios::hex 0x0040

(64 - bit 7) Formato en base 16. Conversión hexadecimal

ios::showbase 0x0080

(128 - bit 8) Visualizar indicador de base numérica. Sólo salida

ios::showpoint 0x0100

(256 - bit 9) Visualizar el punto decimal. Salida float

ios::uppercase 0x0200

(512 - bit 10) Visualizar dígitos hexadecimales en mayúsculas

ios::showpos 0x0400

(1024 - bit 11) Añade un signo + a los números positivos

ios:scientific 0x0800

(2048 - bit 12) Utilizar notación científica para reales

ios::fixed 0x1000

(4096 - bit 13) Utilizar notación coma fija para reales

ios::unitbuf 0x2000

(8192 - bit 14) Limpia los flujos después de la inserción

ios::stdio 0x4000

(16384 - bit 15) Limpia stdout y stderr después de la inserción

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 19 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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; // Salida +12.000000 cout << 3 << endl; // Salida +3 cout << -3.0 << endl; // Salida -3.000000 cout.unsetf(ios::showpoint); // Desactivamos la salida forzosa del punto // decimal

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 20 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

cout << e3 << endl; // Salida +12 cout.unsetf(ios::showpos); // Desactivamos la salida del + cout << 3 << endl; } 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; }

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 21 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

La salida del programa es:

0xd 0x19 0x3 015 031 03 13 25 3 d 19 3 15 31 3 13 25 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= 102 num= 1.23456 i= 66 num= 1.23456 i= 0X66 num= 1.234557E+000 i= 102 num= 1.23456

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 22 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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 Formato de datos numéricos en decimal

endl S Envía carácter de nueva línea

ends S Envía un nulo \0

flush S Vacía un flujo

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.

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 23 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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

Programación Orientada a Objetos 7 – Entrada/salida en C++ - 24 -

Ingeniería Técnica en Informática de Sistemas (3er curso) Departamento de Informática y Automática – Universidad de Salamanca (v1.05 – Feb.2005) © Francisco José García Peñalvo y Juan Andrés Hernández Simón

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; }