Вы находитесь на странице: 1из 215

Fundamentos de Programacin

Curso 2012/2013

Apuntes confeccionados por Juan Carlos Cubero. Universidad de Granada.

El color marrn se utilizar para los ttulos de las secciones, apartados, etc El color azul se usar para los trminos cuya denicin aparece por primera vez. En primer lugar aparecer el trmino en espaol y entre parntesis la traduccin al ingls. El color rojo se usar para destacar partes especialmente importantes

Algunos smbolos usados:

denota contenido que el alumno debe estudiar por su cuenta. Entra como materia en el examen. denota contenido de ampliacin. El texto incluido en la transparencia es de obligada lectura aunque las referencias son de consulta opcional y no entran en el examen. denota contenido de ampliacin, a nivel de experto. No entra en el examen.

Consejos sobre buenas prcticas de programacin

denota cdigo o prcticas de programacin que pueden producir errores lgicos graves

denota cdigo que nos da escalofros de slo verlo.

denota cdigo bien diseado que nos ha de servir de modelo en otras construcciones.

denota algo especialmente importante.

Resea histrica.

Principio de Programacin.

Contenidos
I. Introduccin a la Programacin I.1. El ordenador, algoritmos y programas . . . . . . . . . . . . I.1.1. El Ordenador: Conceptos Bsicos . . . . . . . . . . I.1.2. Lenguajes de programacin . . . . . . . . . . . . . . I.1.3. Datos y Algoritmos . . . . . . . . . . . . . . . . . . . I.1.4. Compilacin . . . . . . . . . . . . . . . . . . . . . . I.2. Especicacin de programas . . . . . . . . . . . . . . . . . I.2.1. Escritura y organizacin de un programa . . . . . . . I.2.2. Elementos bsicos de un lenguaje de programacin I.2.3. Tipos de errores en la programacin . . . . . . . . . I.3. Datos y tipos de datos . . . . . . . . . . . . . . . . . . . . . I.3.1. Representacin en memoria de datos e instrucciones I.3.2. Datos y tipos de datos . . . . . . . . . . . . . . . . . I.4. Operadores y expresiones . . . . . . . . . . . . . . . . . . 1 2 2 3 6 11 13 13 19 22 24 24 26 38 38

I.4.1. Terminologa en Matemticas . . . . . . . . . . . . .

I.4.2. Operadores en Programacin . . . . . . . . . . . . . I.4.3. Expresiones . . . . . . . . . . . . . . . . . . . . . . I.5. Tipos de datos comunes en C++ . . . . . . . . . . . . . . . I.5.1. Rango y operadores aplicables a un tipo de dato . . I.5.2. Los tipos de datos enteros . . . . . . . . . . . . . .

39 41 43 43 44 54 66 69 78 81 87 90

I.5.3. Los tipos de datos reales . . . . . . . . . . . . . . . I.5.4. Operando con tipos numricos distintos . . . . . . . I.5.5. El tipo de dato carcter . . . . . . . . . . . . . . . . I.5.6. El tipo de dato cadena de caracteres . . . . . . . . . I.5.7. El tipo de dato lgico o booleano . . . . . . . . . . . I.5.8. El tipo enumerado . . . . . . . . . . . . . . . . . . . II. Estructuras de Control II.1. Estructura condicional . . . . . . . . . . . . . . . . . . . .

91 92

II.1.1. Estructura condicional simple . . . . . . . . . . . . .

II.1.2. Condicional doble . . . . . . . . . . . . . . . . . . . 103 II.1.3. Anidamiento de estructuras condicionales . . . . . . 109 II.1.4. Construccin de estructuras condicionales . . . . . 122 II.1.5. Estructura condicional mltiple . . . . . . . . . . . . 137 II.2. Estructuras repetitivas . . . . . . . . . . . . . . . . . . . . 143

II.2.1. Bucles controlados por condicin: pre-test y post-test 143 II.2.2. Bucles controlador por contador . . . . . . . . . . . 169

II.2.3. Anidamiento de bucles . . . . . . . . . . . . . . . . . 178 II.2.4. Particularidades de C++ . . . . . . . . . . . . . . . . 187

Tema I

Introduccin a la Programacin
Objetivos: Introducir los conceptos bsicos de programacin, para poder construir los primeros programas. Introducir los principales tipos de datos disponibles en C++ para representar informacin del mundo real. Enfatizar, desde un principio, la necesidad de seguir buenos hbitos de programacin.

Autor: Juan Carlos Cubero. Sugerencias: por favor, enviar un e-mail a JC.Cubero@decsai.ugr.es

Introduccin a la Programacin El ordenador, algoritmos y programas

I.1.
I.1.1.

El ordenador, algoritmos y programas


El Ordenador: Conceptos Bsicos

"Los ordenadores son intiles. Slo pueden darte respuestas". Pablo Picasso

Hardware Software Usuario (User) Programador (Programmer) Lenguaje de Programacin (Programming Language)

Introduccin a la Programacin El ordenador, algoritmos y programas Lenguajes de programacin

I.1.2.

Lenguajes de programacin

Programa (Program) : Es el conjunto de instrucciones especicadas en un lenguaje de programacin concreto, que pueden ejecutarse en un ordenador y que resuelven un problema. Lenguaje de programacin (Programming language) : Lenguaje formal utilizado para comunicarnos con un ordenador e imponerle la ejecucin de un conjunto de rdenes. Cdigo binario (Binary code) :

"There are 10 types of people in the world, those who can read binary, and those who cant".

Introduccin a la Programacin El ordenador, algoritmos y programas Lenguajes de programacin

Lenguaje ensamblador (Assembly language) . Depende del micropocesador (Intel 8086, Motorola 88000, etc) Se usa para programar drivers, microcontroladores (que son circuitos integrados que agrupan microprocesador, memoria y perifricos), compiladores, etc. Se ve en otras asignaturas.

.model small .stack .data Cadena1 DB 'Hola Mundo.$' .code mov ax, @data mov ds, ax mov dx, offset Cadena1 mov ah, 9 int 21h end
Lenguajes de alto nivel (High level language) (C, C++, Java, Lisp, Prolog, Perl, Visual Basic, C#, Go ...) En esta asignatura usaremos C++ (ISO C++).

#include <iostream> using namespace std; int main(){ cout << "Hola Mundo"; }

Introduccin a la Programacin El ordenador, algoritmos y programas Lenguajes de programacin

Resea histrica del lenguaje C++ 1967 Martin Richards: BCPL para escribir S.O. 1970 Ken Thompson: B para escribir UNIX (inicial) 1972 Dennis Ritchie: C 1983 Comit Tcnico X3J11: ANSI C 1983 Bjarne Stroustrup: C++ 1989 Comit tcnico X3J16: ANSI C++ 1990 Internacional Standarization Organization http://www.iso.org Comit tcnico JTC1: Information Technology Subcomit SC-22: Programming languages, their environments and system software interfaces. Working Group 21: C++

http://www.open-std.org/jtc1/sc22/wg21/
2011 Nuevo estndar. Buscar C++11 en Internet. Qu programas se han hecho en C++? Google, Amazon, sistema de reservas areas (Amadeus), omnipresente en la industria automovilstica y area, sistemas de telecomunicaciones, el explorador Mars Rovers, el proyecto de secuenciacin del genoma humano, videojuegos como Doom, Warcraft, Age of Empires, Halo, la mayor parte del software de Microsoft y una gran parte del de Apple, la mquina virtual Java, Photoshop, Thunderbird y Firefox, MySQL, OpenOfce, etc. Entrevista reciente a Bjarne Stroustrup:

http://www.wired.com/thisdayintech/2010/10/1014cplusplus-released/ all/1#ixzz12guDpzz8

Introduccin a la Programacin El ordenador, algoritmos y programas Datos y Algoritmos

I.1.3.

Datos y Algoritmos

Algoritmo (Algorithm) : es una secuencia ordenada de instrucciones que resuelve un problema concreto, atendiendo a las siguientes caractersticas bsicas: Correccin (sin errores). Precisin (no puede haber ambigedad). Repetitividad (en las mismas condiciones, al ejecutarlo, siempre se obtiene el mismo resultado). Finitud (termina en algn momento). Nmero nito de rdenes no implica nitud. Caractersticas esenciales: Validez (resuelve el problema pedido) Eciencia (lo hace en un tiempo aceptable)

Un dato (data) es una representacin simblica de una caracterstica o propiedad de una entidad. Los algoritmos operan sobre los datos. Usualmente, reciben unos datos de entrada con los que operan, y a veces, calculan unos nuevos datos de salida.

Introduccin a la Programacin El ordenador, algoritmos y programas Datos y Algoritmos

Ejemplo. Algoritmo de la media aritmtica de N valores. Datos de entrada: N, valor1, valor2, ..., valorN Datos de salida: media Instrucciones en lenguaje natural: Sumar los N valores y dividir el resultado por N Ejemplo. Algoritmo para la resolucin de una ecuacin de primer grado ax + b = 0 Datos de entrada: a, b Datos de salida: x Instrucciones en lenguaje natural: Calcular x como el resultado de la divisin b/a
Podra mejorarse el algoritmo contemplando el caso de ecuaciones degeneradas

Ejemplo. Algoritmo para el clculo de la hipotenusa de un tringulo rectngulo. Datos de entrada: lado1, lado2 Datos de salida: hipotenusa Instrucciones en lenguaje natural: hipotenusa = lado12 + lado22

Introduccin a la Programacin El ordenador, algoritmos y programas Datos y Algoritmos

Ejemplo. Algoritmo para ordenar una lista de valores numricos. (9, 8, 1, 6, 10, 4) (1, 4, 6, 8, 9, 10) Datos de entrada: el vector Datos de salida: el mismo vector Instrucciones en lenguaje natural: Calcular el mnimo valor de todo el vector Intercambiarlo con la primera posicin Volver a hacer lo mismo con el vector formado por todas las componentes menos la primera. (9, 8, 1, 6, 10, 4) (1, 8, 9, 6, 10, 4) (X, 8, 9, 6, 10, 4) (X, 4, 9, 6, 10, 8) (X, X, 9, 6, 10, 8)

Introduccin a la Programacin El ordenador, algoritmos y programas Datos y Algoritmos

Una vez diseado el algoritmo, pasamos a implementarlo en un lenguaje de programacin concreto.


"First, solve the problem. Then, write the code".

Implementacin de un algoritmo (Algorithm implementation) : Transcripcin a un lenguaje de programacin de un algoritmo. Ejemplo. Implementacin del algoritmo para el clculo de la media (para 4 valores) en C++:

suma = valor1 + valor2 + valor3 + valor4; media = suma / 4;


Ejemplo. Implementacin del algoritmo para el clculo de la hipotenusa:

hipotenusa = sqrt(lado1*lado1 + lado2*lado2);

Un programa incluir la implementacin de uno o ms algoritmos. Ejemplo. Programa para dibujar planos de pisos. Utilizar algoritmos para dibujar cuadrados, de medias aritmticas, salidas grcas en plotter, etc. Muchos de los programas que se vern en FP implementarn un nico algoritmo.

Introduccin a la Programacin El ordenador, algoritmos y programas Datos y Algoritmos

10

Ampliacin:
Uno de los pilares fundamentales de la informtica lo constituye la mquina de Turing (Turing machine) . Es un modelo formal de ordenador basado en un alfabeto, un conjunto de estados y un conjunto de transiciones sobre dichos estados.

La mquina de Turing permite realizar cualquier cmputo que un computador digital sea capaz de realizar Turing demostr que existen problemas que una mquina no puede resolver. Antes de disear la mquina de Turing, ste ayud a descifrar los mensajes encriptados por la mquina Enigma en la segunda guerra mundial. Consultad en Wikipedia la biografa de Turing. Tambin puede consultarse:

http://www.zator.com/Cpp/E0_1_1.htm
La importancia de Turing en el campo de la Informtica es tal que el equivalente a los premios Nobel llevan su nombre: A.M.Turing Award, patrocinado por Intel y Google. Por cierto, el servidor de la ETS Informtica se llama turing.ugr.es

Introduccin a la Programacin El ordenador, algoritmos y programas Compilacin

11

I.1.4.

Compilacin

Al cdigo escrito en un lenguaje concreto se le denomina cdigo fuente (source code) . ste se guarda en cheros de texto normales (en el caso de C++ tienen extensin .cpp).

Pitagoras.cpp

/* Programa simple para el clculo de la hipotenusa de un tringulo rectngulo, aplicando el teorema de Pitgoras */ #include <iostream> // Inclusin de los recursos de E/S #include <cmath> // Inclusin de los recursos matemticos using namespace std; int main(){ double lado1; double lado2; double hipotenusa; // Programa Principal // Declara variables para guardar // los dos lados y la hipotenusa

cout << "Introduzca la longitud del primer cateto: " ; cin >> lado1; cout << "Introduzca la longitud del segundo cateto: "; cin >> lado2; hipotenusa = sqrt(lado1*lado1 + lado2*lado2); cout << "\nLa hipotenusa vale " << hipotenusa << "\n\n" ; }

Introduccin a la Programacin El ordenador, algoritmos y programas Compilacin

12

Pitagoras.cpp es un simple chero de texto. Para obtener el programa ejecutable (el chero en binario que puede ejecutarse en un ordenador) se utiliza un compilador:
Cdigo fuente del programa Programa ejecutable

Compilacin

La extensin del programa ejecutable en Windows es .exe


Cdigo Fuente: Pitagoras.cpp

#include <iostream> using namespace std; int main() { double lado1; .......... cout << "Introduzca la longitud ... cin >> lado1; .......... }
Programa Ejecutable: Pitagoras.exe

Compilador

10011000010000 10010000111101 00110100000001 11110001011110 11100001111100 11100101011000 00001101000111 00011000111100

Introduccin a la Programacin Especicacin de programas

13

I.2.
I.2.1.

Especicacin de programas
Escritura y organizacin de un programa

Los programas en C++ pueden dividirse en varios cheros aunque por ahora vamos a suponer que cada programa est escrito en un nico chero (Pitagoras.cpp). Se pueden incluir comentarios en lenguaje natural.

/* Comentario en varias lneas */ // Comentario 1 sola lnea


El texto de un comentario no es procesado por el compilador. Al principio del chero se indica que vamos a usar una serie de recursos denidos en un chero externo o biblioteca (library)

#include <iostream> #include <cmath>


A continuacin aparece int main(){ que indica que comienza el programa principal. ste se extiende desde la llave abierta {, hasta encontrar la correspondiente llave cerrada. Dentro del programa principal van las sentencias (sentence/statement) que componen el programa. Una sentencia es una parte del cdigo fuente que el compilador puede traducir en una instruccin en cdigo binario. Las sentencias van obligatoriamente separadas por punto y coma (;) El compilador va ejecutando las sentencias secuencialmente de arriba abajo. En el tema II se ver como realizar saltos, es decir, interrumpir la estructura secuencial.

Introduccin a la Programacin Especicacin de programas Escritura y organizacin de un programa

14

Cuando llega a la llave cerrada } correspondiente a main(), y si no han habido problemas, el programa termina de ejecutarse y el Sistema Operativo libera los recursos asignados a dicho programa.

Existen varios tipos de sentencias: Sentencias de declaracin de datos (data) Cada dato que usemos en un programa debe declararse al principio (despus de main), asocindole un tipo de dato concreto.

double lado1; double lado2; double hipotenusa;


Declara tres datos (variables) de tipo real que el programador puede usar en el programa. Sentencias de clculo A travs de la asignacin =

lado1 = 7; lado2 = 5; hipotenusa = sqrt(lado1*lado1 + lado2*lado2);


asigna a la variable hipotenusa el resultado de evaluar lo que aparece a la derecha de la asignacin. Nota. No confundir = con la igualdad en Matemticas

Introduccin a la Programacin Especicacin de programas Escritura y organizacin de un programa

15

Sentencias de Entrada/Salida Sentencias para mostrar informacin en el perifrico de salida establecido por defecto. En FP, dicho perifrico ser la pantalla, pero podra ser un chero en disco o dispositivo externo (impresora, plotter, puerto FireWire, etc.). Se construyen usando cout, que es un recurso externo incluido en la biblioteca iostream.

cout << "Mensaje " << variable;


Lo que haya dentro de un par de comillas dobles se muestra tal cual, excepto los caracteres precedidos de \. Por ejemplo, \n hace que el cursor salte al principio de la lnea siguiente. cout << "Bienvenido. Salto a la siguiente linea ->\n"; cout << "\n<- Empiezo en una nueva linea."; Los nmeros se escriben tal cual (decimales con punto) cout << 3.1415927; Si ponemos una variable, se imprime su contenido.

cout << "\nIntroduzca la longitud del primer cateto: "; ..... hipotenusa = sqrt(lado1*lado1 + lado2*lado2); cout << "\nLa hipotenusa vale ": cout << hipotenusa;
Observad el espacio al nal del mensaje. Qu hara lo siguiente? cout << "hipotenusa"; Podemos usar una nica sentencia: cout << "\nLa hipotenusa vale " << hipotenusa;

Introduccin a la Programacin Especicacin de programas Escritura y organizacin de un programa

16

Aunque no es recomendable, tambin pueden incluirse expresiones como:

cout << "\nLa hipotenusa vale " << sqrt(lado1*lado1+lado2*lado2);


Es mejor almacenar previamente el valor de la expresin en una variable (hipotenusa) y luego utilizarla donde se necesite (por ejemplo, para imprimir su valor) Es importante dar un formato adecuado a la salida de datos en pantalla. El usuario del programa debe entender claramente el signicado de todas sus salidas.

// MAL: totalVentas = 45; numeroVentas = 78; cout << totalVentas << numeroVentas;

// Imprime 4578

// BIEN: cout << "\nSuma total de ventas = " << totalVentas; cout << "\nNmero total de ventas = " << numeroVentas;

Introduccin a la Programacin Especicacin de programas Escritura y organizacin de un programa

17

Sentencias para leer datos desde el dispositivo de entrada establecido por defecto. Por ahora, ser el teclado. Se construyen usando cin, que es un recurso externo incluido en la biblioteca iostream.

cin >> variable;


Por ejemplo, cin >> lado1, espera a que el usuario introduzca un valor real (double) desde el teclado (dispositivo de entrada) y, cuando se pulsa la tecla Intro, lo almacena en la variable lado1. Conforme se va escribiendo el valor, ste se muestra en pantalla, incluyendo el salto de lnea.
 

La lectura de datos con cin puede considerarse como una asignacin en tiempo de ejecucin

Las entradas de datos deben etiquetarse adecuadamente:

// MAL: cin >> lado1; cin >> lado2; // BIEN: cout << "Introduzca la longitud del primer cateto: "; cin >> lado1; cout << "Introduzca la longitud del segundo cateto: "; cin >> lado2;
Cuando la entrada se realiza desde un chero (y no el teclado), la lectura es automtica sin que se espere la tecla Intro.

Introduccin a la Programacin Especicacin de programas Escritura y organizacin de un programa

18

Estructura bsica de un programa (los corchetes delimitan secciones opcionales): [ /* Breve descripcin en lenguaje natural de lo que hace el programa */ ]

[ Inclusin de recursos externos ]

using namespace std; int main(){


[Declaracin de datos]

[Sentencias del programa separadas por ;]

Introduccin a la Programacin Especicacin de programas Elementos bsicos de un lenguaje de programacin

19

I.2.2.

Elementos bsicos de un lenguaje de programacin


Tokens y reglas sintcticas

I.2.2.1.

Cada lenguaje de programacin tiene una sintaxis propia que debe respetarse para poder escribir un programa. Bsicamente, queda denida por: a) Los componentes lxicos (tokens) . Formados por caracteres alfanumricos y/o simblicos. Representan la unidad lxica mnima que el lenguaje entiende. main ; ( == = hipotenusa * Pero por ejemplo, ni ! ni ((* son tokens vlidos. b) Reglas sintcticas (Syntactic rules) : determinan cmo han de combinarse los tokens para formar sentencias. Algunas se especican con tokens especiales (formados usualmente por smbolos): Separador de sentencias ; Para agrupar varias sentencias se usa { }
Se ver su uso en el tema II. Por ahora, sirve para agrupar las sentencias que hay en el programa principal

Para agrupar expresiones (frmulas) se usa ( ) = sqrt( (lado1*lado1) + (lado2*lado2) );

Introduccin a la Programacin Especicacin de programas Elementos bsicos de un lenguaje de programacin

20

I.2.2.2.

Palabras reservadas

Suelen ser tokens formados por caracteres alfabticos. Tienen un signicado especco para el compilador, y por tanto, el programador no puede denir variables con el mismo identicador. Algunos usos:

main
Para denir tipos de datos como por ejemplo double Para establecer el ujo de control (control ow) , es decir, para especicar el orden en el que se han de ejecutar las sentencias, como if, while, for etc. Estos se vern en el tema 2.

//

Errores sintcticos

int main(){ double main; // main es un nombre de dato incorrecto double double; // double es un nombre de dato incorrecto }

Introduccin a la Programacin Especicacin de programas Elementos bsicos de un lenguaje de programacin

21

Palabras reservadas comunes a C (C89) y C++


auto do goto signed break case char enum long const extern continue default oat for short union

double else if sizeof int static

register return typedef

struct switch

unsigned void

volatile while

Palabras reservadas adicionales de C++


and class false not_eq and_eq compl friend operator asm bitand bitor bool catch export not

const_cast delete inline or

dynamic_cast explicit new

mutable namespace or_eq this virtual private throw wchar_t

protected public true xor try xor_eq

reinterpret_cast static_cast template typeid typename using

Palabras reservadas aadidas en C99


_Bool _Complex _Imaginary inline restrict

Introduccin a la Programacin Especicacin de programas Tipos de errores en la programacin

22

I.2.3.

Tipos de errores en la programacin

Errores en tiempo de compilacin (Compilation error) Ocasionados por un fallo de sintaxis en el cdigo fuente. No se genera el programa ejecutable.

/* CONTIENE ERRORES #include <iostre am> USING namespace std; int main{}( double lado1: double lado 2, double hipotenusa:

*/

lado1 = 2; lado2 = 3 hipotenusa = sqrt(lado1**lado1 + ladp2*ladp2); cout << "La hipotenusa vale << hipotenusa; )

Introduccin a la Programacin Especicacin de programas Tipos de errores en la programacin

23

"Software and cathedrals are much the same. First we build them, then we pray".

Errores en tiempo de ejecucin (Execution error) Se ha generado el programa ejecutable, pero se produce un error durante la ejecucin.

int dato_entero; int otra_variable; dato_entero = 0; otra_variable = 7 / dato_entero;


Errores lgicos (Logic errors) Se ha generado el programa ejecutable, pero el programa ofrece una solucin equivocada.

......... lado1 = 4; lado2 = 9; hipotenusa = sqrt(lado1+lado1 + lado2*lado2); .........

Introduccin a la Programacin Datos y tipos de datos

24

I.3.
I.3.1.

Datos y tipos de datos


Representacin en memoria de datos e instrucciones

Un programa realiza instrucciones y opera con datos. Una vez compilado el programa, todo son combinaciones adecuadas de 0 y 1.
MEMORIA MASIVA datos e instrucciones

MEMORIA PRINCIPAL 0101100 11110110 00000001 10100001 0001111 11100011 10100100 10111001 1111111 00111111 11010010 00100100 instrucciones datos

ENTRADA datos e instrucciones

SALIDA datos

UNIDAD DE CONTROL

UNIDAD ARITMETICO-LOGICA

CPU

Introduccin a la Programacin Datos y tipos de datos Representacin en memoria de datos e instrucciones

25

Datos

"Juan Prez" 1 0 1 1 .. 0 1 1

75225813

1 1 0 1 .. 0 0 0

3.14159

0 0 0 1 .. 1 1 1

Instrucciones

Abrir Fichero 0 0 0 1 .. 1 1 1

Imprimir Nos centramos en los datos.

1 1 0 1 .. 0 0 0

Introduccin a la Programacin Datos y tipos de datos Datos y tipos de datos

26

I.3.2.

Datos y tipos de datos

Al trabajar con un lenguaje de alto nivel, no haremos referencia a la secuencia de 0 y 1 que codican un valor concreto, sino a lo que representa para nosotros. Un dato (data) es un conjunto de celdas de memoria que tiene asociado un nombre -identicador (name) - y un contenido -valor (value) -.

NombreEmpleado NumeroHabitantes Pi

Juan Prez 75225813

3.14159

Un programa necesitar representar datos de diverso tipo (cadenas de caracteres, enteros, reales, etc). Para cada tipo, el lenguaje ofrece un tipo de dato (data type) .

string NombreEmpleado; long NumeroHabitantes; double Pi; NombreEmpleado = "Juan Prez"; NumeroHabitantes = 75225813; Pi = 3.14159;

Introduccin a la Programacin Datos y tipos de datos Datos y tipos de datos

27

Por ejemplo, en C++: Enteros : int, long, ... Numricos Reales : float, double, ... Caracteres : char Simples Lgico : bool Puntero : * Enumerado : enum Vectores y matrices Cadena de caracteres : Vectores de caracteres, Compuestos string Registros Clases Por ahora slo usaremos double, int, char y string.

Tipos

Introduccin a la Programacin Datos y tipos de datos Datos y tipos de datos

28

I.3.2.1.

Literales

Son la especicacin de un valor concreto de un tipo de dato. Dependiendo del tipo, tenemos: Literales numricos (numeric literals) : son tokens numricos. Para representar datos reales, se usa el punto . para especicar la parte decimal: 2 3 3.5 Literales de cadenas de caracteres (string literals) : Son cero o ms caracteres encerrados entre comillas dobles: "Hola" Literales de otros tipos, como literales de caracteres (character literals) 'a', Literales lgicos (boolean literals) true, etc. I.3.2.2. Declaracin de variables

Cada variable que se use en un programa debe declararse al principio (despus de main), asocindole un tipo de dato concreto y un identicador. Al declarar una variable, el compilador reserva una zona de memoria para trabajar con ella. Ninguna otra variable podr usar dicha zona. Cada variable debe estar asociado a un nico tipo de dato (el tipo no puede cambiarse durante la ejecucin). El valor que se le puede asignar a una variable depende del tipo de dato con el que es declarado.

Introduccin a la Programacin Datos y tipos de datos Datos y tipos de datos

29

Formas de declarar variables: Un nico identicador por declaracin:

<tipo> <identificador1>; <tipo> <identificador2>; ... double lado1; double lado2; double hipotenusa;
Varios identicadores por declaracin:

<tipo> <identificadores separados por coma>; double lado1, lado2, hipotenusa;


Opcionalmente, se puede dar un valor inicial durante la declaracin:

<tipo> <identificador> = <valor_inicial>; <tipo> <identificador> = <valor_inicial>, <identificador>...; double dato = 4.5; equivale a: double dato; dato = 4.5;

Introduccin a la Programacin Datos y tipos de datos Datos y tipos de datos

30

Cuando se declara una variable y no se inicializa, sta no tiene ningn valor asignado por defecto. El valor almacenado es indeterminado y puede variar de una ejecucin a otra. Lo representaremos grcamente por ?

/* Programa para calcular la retencin a aplicar en el sueldo de un empleado */ #include <iostream> using namespace std; int main(){ double salario_bruto; // Salario bruto, en euros double retencion; // Retencin a aplicar, en euros salario_bruto
?

retencion
?

cout << "Introduzca salario bruto: "; cin >> salario_bruto; retencion = salario_bruto * 0.18; cout << "Retencin a aplicar: " << retencion; } salario_bruto
32538.0

retencion
4229.94

Introduccin a la Programacin Datos y tipos de datos Datos y tipos de datos

31

Un error lgico muy comn es usar una variable no asignada:

int main(){ double salario_bruto; // Salario bruto, en euros double retencion; // Retencin a aplicar, en euros retencion = salario_bruto * 0.18; // :-(

cout << "Retencin a aplicar: " << retencion; }


Imprimir un valor indeterminado. I.3.2.3. Datos constantes

Podramos estar interesados en usar variables a las que slo permitimos tomar un nico valor, jado de antemano. Es posible con una constante (constant) . Se declaran como sigue:

const <tipo><identif>= <expresin>;


A las constantes se les aplica las mismas consideraciones que hicimos con las variables, sobre tipo de dato y reserva de memoria. Suelen usarse identicadores slo con maysculas para diferenciarlos de las variables.

Introduccin a la Programacin Datos y tipos de datos Datos y tipos de datos

32

/* Programa que pide el radio de una circunferencia e imprime su longitud y el rea del crculo */ #include <iostream> using namespace std; int main() { const double PI = 3.1416; double area, radio, longitud; PI = 3.15; // <- Error de compilacin :-) cout << "Introduzca el valor del radio "; cin >> radio; area = PI * radio * radio; longitud = 2 * PI * radio; cout << "El rea vale " << area; cout << "La longitud vale " << longitud; }
Ventaja declaracin de constantes: Informacin al propio programador. Imposibilidad de cambiarlo por error (PI). Cdigo menos propenso a errores. Para cambiar el valor de PI, (por ejemplo por 3.1415927), slo hay que tocar en la lnea de declaracin de la constante.

Introduccin a la Programacin Datos y tipos de datos Datos y tipos de datos

33

/* Programa para calcular la retencin a aplicar en el sueldo de un empleado */ #include <iostream> int main(){ const double IRPF = 0.18; // Porcentaje gravamen fiscal double retencion; // Retencin a aplicar, en euros double salario_bruto; // Salario bruto, en euros

salario_bruto
?

IRPF
0.18

retencion
?

cout << "Introduzca salario bruto: "; cin >> salario_bruto; retencion = salario_bruto * IRPF; cout << "\n Retencin a aplicar: " << retencion; }

salario_bruto
32538

IRPF
0.18

retencion
4229.94

Introduccin a la Programacin Datos y tipos de datos Datos y tipos de datos

34

Formalmente, al conjunto de variables y constantes, se le denomina datos. As pues, los datos se pueden clasicar como: variables datos constantes Las variables son datos cuyo valor puede variar a lo largo del programa, p.e., lado1. Las constantes son datos cuyo contenido no vara a lo largo de la ejecucin del programa, p.e., el nmero .

Una sintaxis de programa algo ms completa: [ /* Breve descripcin en lenguaje natural de lo que hace el programa */ ]

[ Inclusin de recursos externos ]

using namespace std; int main(){


[Declaracin de constantes] [Declaracin de variables]

[Sentencias del programa separadas por ;]

Introduccin a la Programacin Datos y tipos de datos Datos y tipos de datos

35

I.3.2.4.

Normas para la eleccin del identicador

Cada dato necesita un identicador nico. Un identicador de un dato es un token formado por caracteres alfanumricos con las siguientes restricciones: Debe empezar por una letra o subrayado (_) No pueden contener espacios en blanco ni ciertos caracteres especiales como letras acentuadas, la letra ee, las barras \ o /, etc. Ejemplo: lado1 lado2 precio_con_IVA El compilador determina la mxima longitud que pueden tener (por ejemplo, 31 caracteres) Sensibles a maysculas y minsculas. lado y Lado son dos identicadores distintos. No se podr dar a un dato el nombre de una palabra reservada. No es recomendable usar el nombre de algn identicador usado en las bibliotecas estndar (por ejemplo, cout)

#include <iostream> using namespace std; int main(){ double cout; // Error de sintaxis double main; // Error de sintaxis

Ejercicio. Determinar cules de los siguientes son identicadores vlidos. Si son invlidos explicar por qu. a) registro1 b) 1registro c) archivo_3 d) main

e) nombre y direccion

f) direccin

g) diseo

Introduccin a la Programacin Datos y tipos de datos Datos y tipos de datos

36

Consejos muy importantes para elegir el identicador de un dato: El identicador de un dato debe reejar su semntica (contenido). Por eso, salvo excepciones (como las variables contadoras de los bucles -tema II-) no utilizaremos nombres con pocos caracteres

v, l1, l2, hp voltaje, lado1, lado2, hipotenusa


No utilizaremos nombres genricos

aux, vector1 copia, calificaciones


Usaremos minsculas para los datos variables. Las constantes se escribirn en maysculas. Los nombres compuestos se separarn con subrayado _:

precioventapublico, tasaanual precio_venta_publico, tasa_anual


No se nombrarn dos datos con identicadores que dieran nicamente en la capitalizacin, o un slo carcter.

cuenta, cuentas, Cuenta cuenta, coleccion_cuentas, cuenta_ppal


Hay una excepcin a esta norma. Cuando veamos las clases, podremos denir una con el nombre Cuenta y un objeto instancia de dicha clase con el nombre cuenta. Cuando veamos clases, funciones y mtodos, stos se escribirn con la primera letra en mayscula. Los nombres compuestos se separarn con una mayscula. Clase CuentaBancaria, Mtodo Ingresa

Introduccin a la Programacin Datos y tipos de datos Datos y tipos de datos

37

En el examen, se baja puntos por no seguir las anteriores normas.

Introduccin a la Programacin Operadores y expresiones

38

I.4.
I.4.1.

Operadores y expresiones
Terminologa en Matemticas

Notaciones usadas en los operadores matemticos: Notacin preja (Prex notation) . El operador va antes de los argumentos. Estos suelen encerrarse entre parntesis. seno(3), tangente(x), media(valor1, valor2) Notacin inja (Inx notation) . El operador va entre los argumentos. 3+5 x/y Segn el nmero de argumentos, diremos que un operador es: Operador unario (Unary operator) . Slo tiene un argumento: seno(3), tangente(x) Operador binario (Binary operator) . Tienes dos argumentos: media(valor1, valor2) 3+5 x/y Operador n-ario (n-ary operator) . Tiene ms de dos argumentos.

Introduccin a la Programacin Operadores y expresiones Operadores en Programacin

39

I.4.2.

Operadores en Programacin

Los lenguajes de programacin proporcionan operadores que permiten manipular los datos. Se denotan a travs de tokens alfanumricos o simblicos. Suelen devolver un valor y actan sobre ciertos datos (variables o constantes), literales y sobre el resultado que dan otros operadores. Tipos de operadores: Los denidos en el ncleo del compilador. No hay que incluir ninguna biblioteca Suelen usarse tokens simblicos para su representacin y suelen ser injos Ejemplos: + (suma), - (resta), * (producto), etc. Los denidos en bibliotecas externas. Por ejemplo, cmath Suelen usarse tokens alfanumricos para su representacin y suelen ser prejos. Si hay varios argumentos se separan por una coma.

sqrt(4)

sin(6.4)

pow(3,6)

Tradicionalmente se usa el trmino operador (operator) a secas para denotar los primeros, y el trmino funcin (function) para los segundos. A los argumentos de las funciones se les denomina parmetros (parameter) .

Introduccin a la Programacin Operadores y expresiones Operadores en Programacin

40

int main() { const double PI = 3.1415926; double area, radio; cout << "Introduzca el valor del radio "; cin >> radio; // Asignaciones vlidas: area = PI * pow(radio, 2); area = PI * radio * radio;
En general:

variable = Expresin;
Primero se evala la expresin en la parte derecha de la asignacin y luego se realiza la asignacin.

Introduccin a la Programacin Operadores y expresiones Expresiones

41

I.4.3.

Expresiones

Una expresin (expression) es una combinacin de datos y operadores sintcticamente correcta, que el compilador evala y devuelve un valor.

3 3+5 lado1 lado1*lado1 lado1*lado1 + lado2*lado2 sqrt(lado1*lado1 + lado2*lado2)


Las expresiones pueden aparecer a la derecha de una asignacin, pero no a la izquierda. 3+5 = lado; // Error de compilacin Qu hara lo siguiente?

double dato = 4; dato = dato + 3;


Una expresin NO es una sentencia de un programa: Expresin: sqrt(lado1*lado1 + lado2*lado2) Sentencia: hipotenusa = sqrt(lado1*lado1 + lado2*lado2); As pues, los operadores y funciones actan, en general, sobre expresiones.

Introduccin a la Programacin Operadores y expresiones Expresiones

42

Cuando el compilador evala una expresin, devuelve un valor de un tipo de dato (entero, real, carcter, etc.). Diremos que la expresin es de dicho tipo de dato. Por ejemplo:

3 + 5 es una expresin entera 3.5 + 6.7 es una expresin de reales int main(){ double dato_real; int dato_entero; dato_real = 3.5 + 6.7; datos_entero = 3 + 5; ...... }
Nota. Cuando se usa una expresin dentro de cout, el compilador detecta el tipo de dato resultante y la imprime de forma adecuada.

cout << "\nResultado = " << 3+5; cout << "\nResultado = " << 3.5+6.7;
Imprime en pantalla:

Resultado = 8 Resultado = 10.2

Introduccin a la Programacin Tipos de datos comunes en C++

43

I.5.
I.5.1.

Tipos de datos comunes en C++


Rango y operadores aplicables a un tipo de dato

El comportamiento de un tipo de dato viene dado por: El rango (range) de valores que puede representar, que depende de la cantidad de memoria que dedique el compilador a su representacin interna. Intuitivamente, cuanta ms memoria se dedique para un tipo de dato, mayor ser el nmero de valores que podremos representar. El conjunto de operadores que pueden aplicarse a los datos de ese tipo. Ampliacin:
La cantidad de memoria que el compilador asigna a cada tipo se puede consultar con el operador sizeof(<tipo>) cuyo resultado es un entero que contiene el nmero de bytes asignados a <tipo>. sizeof es un operador pues est en el ncleo del compilador, pero se usa en forma preja, encerrando el argumento entre parntesis, como las funciones. Los valores mnimos y mximos que se pueden representar para cada tipo, se pueden consultar en los cheros climits y cfloat. Consultad tambin:

http://msdn2.microsoft.com/en-us/library/d4zh6te4.aspx

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos enteros

44

I.5.2.
I.5.2.1.

Los tipos de datos enteros


Representacin de los enteros

Propiedad fundamental: Cualquier entero puede descomponerse como la suma de determinadas potencias de 2. 53 = 0 215 +0 214 +0 213 +0 212 +0 211 +0 210 +0 29 +0 28 +0 27 + +0 26 + 1 25 + 1 24 + 0 23 + 1 22 + 0 21 + 1 20 La representacin en binario sera la secuencia de los factores (1,0) que acompaan a las potencias: 0000000000110101 Dos elementos a combinar: 1, 0 r posiciones. Por ejemplo, r = 16 Se permiten repeticiones e importa el orden 0000000000110101 = 0000000000110110 Nmero de datos distintos representables = 2r Se conoce como bit a la aparicin de un valor 0 o 1. Un byte es una secuencia de 8 bits. Ampliacin:
La forma fcil de representar el signo sera aadiendo otro bit al principio para indicar si es positivo o negativo (bit de signo). Los ordenadores actuales usan otras tcnicas que agilizan los cmputos. Buscar en Internet: Representacin de nmeros con signo

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos enteros

45

I.5.2.2.

Rango de los enteros

El rango de un deenterointeger es un subconjunto del conjunto matemtico Z . La cardinalidad depender del nmero de bits (r ) que cada compilador utiliza para su almacenamiento. Los compiladores suelen ofrecer distintos tipos enteros. En C++: short, int, long, __int64, etc. El ms usado es int. El estndar de C++ no obliga a los compiladores a usar un tamao determinado. Lo usual es que un int ocupe la longitud de la palabra (word) del segmento de datos del sistema operativo. Hoy en da, lo usual es 32 bits (8 bytes) y 64 bits (16 bytes). En el caso de 32 bits el rango de un int es: 232 232 , 1 = [2147483648, 2147483647] 2 2

int entero; entero = 53;


Cuando necesitemos un entero mayor, podemos usar __int64. Ocupa 64 bits (16 bytes) y el rango es: [9223372036854775808, 9223372036854775807]

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos enteros

46

I.5.2.3.

Literales enteros

Un literal (literal) es la especicacin (dentro del cdigo fuente) de un valor concreto de un tipo de dato. Los literales enteros (integer literals) se construyen con tokens formados por smbolos numricos. Pueden empezar con un signo -

53

-406778

Nota. En el cdigo se usa el sistema decimal (53) pero internamente, el ordenador usa el cdigo binario (000000000110101) Qu tipo de dato se usa para representar un literal entero? Depende de la memoria reservada y de los tipos disponibles en cada compilador. El compilador usar el tipo de dato que se ajuste al tamao del literal entero. As, si un compilador usa 32 bits para un int, 600000000 ser un literal de tipo int.

int entero; entero = 600000000; // int = int __int64 gran_entero; gran_entero = 600000000000000; // __int64 = __int64
La asignacin en el cdigo de un literal demasiado grande provocar un error de compilacin:

int entero; entero = 60000000000000000000; // Error compilacin

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos enteros

47

I.5.2.4.

Operadores

Operadores binarios

suma, resta, producto, divisin entera y mdulo. El operador mdulo (%) representa el resto de la divisin entera Devuelven un entero. Binarios. Notacin inja: a*b

int n = n = n = n = n = n = n = n = n = n = 5 /

n; 5 * 7; n + 1; 25 / 9; 25 % 9; 5 / 7; 7 / 5; 173 / 10; 5 % 7; 7 % 5; 173 % 10; 7 = n;

// // // // // // // // // // //

Asigna a la variable n Asigna a la variable n Asigna a la variable n Asigna a la variable n Asigna a la variable n Asigna a la variable n Asigna a la variable n Asigna a la variable n Asigna a la variable n Asigna a la variable n Sentencia Incorrecta.

el el el el el el el el el el

valor valor valor valor valor valor valor valor valor valor

35 36 2 7 0 1 17 5 2 3

Operaciones usuales: Extraer el dgito menos signicativo: 5734 % 10 4 Truncar desde el dgito menos signicativo: 5734 / 10 573

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos enteros

48

Operadores unarios de incremento y decremento

++ y --

Unarios de notacin postja.

Incrementan y decrementan, respectivamente, el valor de la variable entera sobre la que se aplican (no pueden aplicarse sobre una expresin).

<variable>++;

<variable>--;

/* Incrementa la variable en Es equivalente a: <variable> = <variable> + /* Decrementa la variable en Es equivalente a: <variable> = <variable> // Asigna 5 a dato // Asigna 6 a dato

1 1; */ 1 1; */

int dato = 4; dato = dato+1; dato++;

Operador unario de cambio de signo

Unario de notacin preja.

Cambia el signo de la variable sobre la que se aplica.

int dato = 4, dato_cambiado; dato_cambiado = -dato; dato_cambiado = -dato_cambiado;

// Asigna -4 a dato_cambiado // Asigna 4 a dato_cambiado

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos enteros

49

I.5.2.5.

Expresiones enteras

Son aquellas expresiones, que al evaluarlas, devuelven un valor entero.

entera

56

(entera/4+56)%3

Cmo evala el compilador la siguiente expresin?

3 + 5 * 7;
Posibilidad 1: 1. Primero hacer 3+5 2. Despus, el resultado se multiplica por 7 El resultado sera: 56 Posibilidad 2: 1. Primero hacer 5*7 2. Despus, el resultado se suma a 3 El resultado sera: 38 La forma que adopta el compilador depende de la precedencia de los operadores. Ante la duda, forzad la evaluacin deseada mediante la utilizacin de parntesis:

dato = 3+(5*7);

dato = (3+5)*7;

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos enteros

50

Reglas de precedencia:

() - (operador unario de cambio de signo) * / % + Cualquier operador de una la superior tiene ms prioridad que cualquiera de la la inferior.

variable = 3+5*7;

// equivale a 3+(5*7)

Los operadores de una misma la tienen la misma prioridad. Se evalan de izquierda a derecha segn aparecen en una expresin.

variable = 3/5*7;

// equivale a (3/5)*7

Ejercicio. Teniendo en cuenta el orden de precedencia de los operadores, indicad el orden en el que se evaluaran las siguientes expresiones: a) a + b * c -d b) a * b / c c) a * c % b - d

Ejemplo. Incrementar el salario en 100 euros y calcular el nmero de billetes de 500 euros a usar en el pago.

int salario, num_bill500; salario = 43000; num_bill500 = (salario + 100) / 500; // ok num_bill500 = salario + 100 / 500; // Error lgico

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos enteros

51

I.5.2.6.

Trabajando con tamaos distintos

En una expresin podemos usar distintos tipos de datos.

int entero_normal; __int64 entero_grande, otro_entero_grande; entero_normal = 45; entero_grande = 600000000000000; otro_entero_grande = entero_normal * entero_grande;
En la expresin

entero_normal * entero_grande
usamos dos tipos enteros distintos.
#

"

Para evaluar el resultado de una expresin que contenga datos con tipos distintos, el compilador usar el tipo adecuado que sea capaz de albergar el resultado.

Para albergar el producto de un entero normal y otro grande, necesita un tipo entero grande. Hecho el cmputo, ya puede asignar el resultado a la variable otro_entero_grande. Recordad: Primero, se evala la expresin (usando el tipo adecuado) Segundo, se realiza la asignacin

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos enteros

52

I.5.2.7.

Problemas de desbordamiento

Recordemos que con un literal demasiado grande, el compilador da un error al intentar asignarlo a una variable. Pero al trabajar con datos arbitrarios el compilador no puede realizar ninguna comprobacin. Por tanto, es fcil salirse del rango representable. En este caso, se produce un desbordamiento aritmtico (arithmetic overow) y el resultado es un valor impredecible. Se produce un error lgico.

int entero, incremento; __int64 entero_grande; entero = 600000000000; // Error Compilacin :-) entero = 600000000; // Correcto. "Le cabe" incremento = 1000; entero_grande = entero * incremento // Correcto: __int64 = __int64 entero = entero * incremento; // Desbordamiento:
El compilador es capaz de evaluar la expresin

int = __int64

entero * incremento 600000000 * 1000


El resultado 600000000000 lo almacena temporalmente en un __int64. El problema viene al hacer la asignacin de una expresin de tipo __int64 a una variable de tipo int. En general, debemos tener cuidado con las asignaciones a datos de un tipo ms pequeo que la expresin de la asignacin. Algunos compiladores pueden advertir de este hecho, durante el proceso de compilacin, con un aviso (warning) (pero no es un error de compilacin).

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos enteros

53

I.5.2.8.

Un int no es siempre un entero de 32 bits con signo

Una de las principales crticas al estndar C++ es que cada compilador tiene cierto margen de maniobra y puede implementar cada tipo de dato de forma distinta. Una restriccin fundamental es:

1 byte

==

char <=

short <=

int

<= long

Por tanto, podra ser que un int fuese un entero de 32 bits con signo en un compilador y en otro fuese un entero de 16 bits con signo. Obviamente, esto puede ocasionar problemas de desbordamiento como hemos visto en la seccin anterior. Los cheros de cabecera <climits> y <float.h> contienen deniciones de los rangos de valor de todos los tipos fundamentales. Ampliacin:
Consultad las restricciones bsicas en:

http://www.zator.com/Cpp/E2_2_4c.htm
y una referencia ms avanzada en:

http://www.zator.com/Cpp/E2_2_4.htm

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos reales

54

I.5.3.

Los tipos de datos reales

Un dato de tipo real (oat) tiene como rango un subconjunto nito de R Parte entera de 4,56 4 Parte real de 4,56 56 C++ ofrece distintos tipos para representar valores reales. Principalmente, float (usualmente 32 bits) y double (usualmente 64 bits).

double valor_real; valor_real = 541.341;


I.5.3.1. Literales reales

Son tokens formados por dgitos numricos y con un nico punto que separa la parte decimal de la real. Pueden llevar el signo - al principio.

800.457
Importante:

4.0

-3444.5

El literal 3 es un entero. El literal 3.0 es un real. Los compiladores suelen usar el tipo double para representar literales reales. Tambin se puede utilizar notacin cientca:

5.32e+5 representa el nmero 5,32 105 = 532000 42.9e-2 representa el nmero 42,9 102 = 0,429

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos reales

55

I.5.3.2.

Representacin de los reales

Cmo podra el ordenador representar 541,341? Lo fcil sera: Representar la parte entera 541 en binario Representar la parte real 341 en binario De esa forma, con 64 bits (32 bits para cada parte) podramos representar: Partes enteras en el rango [2147483648, 2147483647] Partes reales en el rango [2147483648, 2147483647] Sin embargo, la forma usual de representacin no es as. Se utiliza la representacin en coma otante (oating point) . La idea es representar un valor y la escala. En aritmtica decimal, la escala se mide con potencias de 10: 42,001 42001 valor = 4,2001 escala = 10 valor = 4,2001 escala = 104

0,42001 valor = 4,2001 escala = 101 El valor se denomina mantisa (mantissa) y el coeciente de la escala exponente (exponent) . En la representacin en coma otante, la escala es 2. A grosso modo se utilizan m bits para la mantisa y n bits para el exponente. La forma explcita de representacin en binario se ver en otras asignaturas. Podemos adelantar que la representacin de la parte real se hace en potencias inversas de 2. Por ejemplo, 1011 representara 1 1 21 +0 1 22 +1 1 23 +1 1 24 =

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos reales

56

=1

1 2

+0

1 4

+1

1 8

+1

1 16

= 0,6875

Problema: Si bien un entero se puede representar de forma exacta como suma de potencias de dos, un real slo se puede aproximar con suma de potencias inversas de dos. Valores tan sencillos como 0,1 o 0,01 no se pueden representar de forma exacta. 0,1 1 1 24 +0 1 25 +0 1 26 +0 1 27 +0 1 28 +

Por tanto: Todas las operaciones realizadas con los reales pueden devolver valores que slo sean aproximados!

Especial cuidado tendremos con operaciones del tipo

Repite varias veces Ir sumndole a una variable_real varios valores reales;


ya que los errores de aproximacin se irn acumulando.

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos reales

57

I.5.3.3.

Rango y Precisin

La codicacin en coma otante separa el valor de la escala. Esto permite trabajar (en un mismo tipo de dato) con magnitudes muy grandes y muy pequeas.

double valor_real; valor_real = 100000000000000000000.0; valor_real = 0.000000000000000000001;

// ok // ok!

double masa_tierra_kg, masa_electron_kg; masa_tierra_kg = 5.98e24; // ok masa_electron_kg = 9.11e-31; // ok


Pero el precio a pagar es muy elevado: muy poca precisin (tanto en la parte entera como la real)

double valor_real; valor_real = 123456789012345.0; // :-) valor_real = 12345678901234567.0; // :-( // Se almacenar un valor aproximado. // Por ejemplo: 12345678901234563.0;
La regla a usar es que con 32 bits, se consigue una precisin aproximada de 7 dgitos y con 64 bits, se consiguen aproximadamente 16 dgitos.

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos reales

58

valor_real = 0.12345678901234567; // Se almacenar un valor aproximado. Por ejemplo: // 0.12345678901234563; valor_real = 0.1; // Ya lo vimos antes // Tambin se almacenar un valor aproximado. // Por ejemplo: 0.99999899897
Cuanto mayor sea la parte entera a representar, menor ser la precisin en decimales que obtendremos (sin contar que, adems, muchos decimales como 0.1 no se pueden representar de forma exacta) Por ejemplo, usando 32 bits, hay aproximadamente 8388607 nmeros entre 1,0 y 2,0, mientras que slo hay 8191 entre 1023,0 y 1024,0 Debido a la poca precisin, los programas nancieros no trabajan con reales en coma otante. Soluciones: Trabajar con enteros y potencias de 10.

int salario; salario = 175023; // 1750 euros y 23 cntimos salario = 143507; // 1435 euros y 7 cntimos salario = 130000; // 1300 euros
Usar tipos o clases especcas (BCD por ejemplo)

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos reales

59

En resumen:
' $

Los tipos enteros representan datos enteros de forma exacta. Los tipos reales representan la parte entera de forma exacta, siempre que trabajemos con menos de 16 dgitos (en una representacin con 64 bits) La parte real ser slo aproximada. Adems, la aproximacin ser mejor cuanto menor sea la parte entera del nmero.

&

Los reales en coma otante tambin permiten representar valores especiales como innito (innity) y una indeterminacin (undened) NaN (Not a Number)

double valor_real, divisor = 0.0; valor_real = 17.5 / divisor; // Almacena INF valor_real = 1.5 / valor_real; // Almacena 0.0 valor_real = divisor / divisor; // Almacena NaN valor_real = 1.5 / valor_real; // Almacena NaN

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos reales

60

I.5.3.4.

Operadores

+, -, *, /
Binarios, de notacin inja. Tambin se puede usar el operador unario de cambio de signo (-). Aplicados sobre reales, devuelven un real.

double real; real = 5.0 * 7.0; real = 5.0 / 7.0;

// Asigna a real el valor 35.0 // Asigna a real el valor 0.7142857

Cuidado! El comportamiento del operador / depende del tipo de los operandos: si todos son enteros, es la divisin entera. Si todos son reales, es la divisin real.

double real = real = real =

real; 5.0 / 7.0; 5 / 7; 5 / 7.0;

// Asigna a real el valor 0.7142857 // Asigna a real el valor 0 // <- Lo vemos despus

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos reales

61

I.5.3.5.

Funciones estndar

Hay algunas bibliotecas estndar que proporcionan funciones que trabajan sobre datos numricos (enteros o reales) y que suelen devolver un real. Por ejemplo, cmath

pow(), cos(), sin(), sqrt(), tan(), log(), log10(), fabs(), ....


Todos los anteriores son unarios excepto pow, que es binario. Devuelven un real.

#include <iostream> #include <cmath> using namespace std; int main(){ double abscisa, ordenada; abscisa = 5.4; ordenada = sqrt(abscisa); ordenada = pow(4.3, abscisa); }

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos reales

62

I.5.3.6.

Expresiones reales

Son expresiones cuyo resultado es un nmero real.

sqrt(abscisa) es una expresin real pow(4.3, abscisa) es una expresin real sqrt(b*b - 4.0*a*c) es una expresin real
En general, diremos que las expresiones aritmticas (arithmetic expression) o numricas son las expresiones o bien enteras o bien reales. Precedencia de operadores:

() - (operador unario de cambio de signo) * / + ' $

Consejo:

&

Para facilitar la lectura de las frmulas matemticas, evitad el uso de parntesis cuando est claro cul es la precedencia de cada operador.

b +

b2 4ac

2a

-b+sqrt(b*b-4.0*a*c)/2.0*a ((-b)+(sqrt(b*b - (4.0*a)*c)))/(2.0*a) (-b + sqrt(b*b - 4.0*a*c))/(2.0*a)

INCORRECTO CORRECTO RECOMENDADO

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos reales

63

Ejemplo. Calcular las races de una ecuacin de 2o grado. p(x) = ax2 + bx + c = 0 Algoritmo: Entradas: Los parmetros de la ecuacin a, b, c. Salidas: Las races de la parbola r 1, r 2 Descripcin: Calcular r 1, r 2 en la forma siguiente: b + b2 4ac b b2 4ac

r1 =

2a

r2 =

2a

p(x) = ax2 + bx + c
5 p(x)

-5

-10

-15

-20 -4 -2 0 2 4

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos reales

64

#include <iostream> #include <cmath> using namespace std; int main(){ double a, b, c; // Parmetros de la ecuacin double raiz1, raiz2; // Races obtenidas cout << "\nIntroduce coeficiente de 2o grado: "; cin >> a; cout << "\nIntroduce coeficiente de 1er grado: "; cin >> b; cout << "\nIntroduce coeficiente independiente: "; cin >> c; raiz1 = ( -b + sqrt( b*b-4*a*c ) ) / (2*a); raiz2 = ( -b - sqrt( b*b-4*a*c ) ) / (2*a); cout << "\nLas races son" << raiz1 << " y " << raiz2; }

Principio de Programacin: Una nica vez (Once and only once)

Cada descripcin de comportamiento debe aparecer una nica vez en nuestro programa.

Dicho de otra forma: JAMS ha de repetirse cdigo La repeticin de cdigo hace que los programas sean difciles de actualizar ya que cualquier cambio ha de realizarse en todos los sitios en los que est repetido el cdigo.

Introduccin a la Programacin Tipos de datos comunes en C++ Los tipos de datos reales

65

Para no repetir cdigo usamos una variable para almacenar el valor de la expresin que se repite:

#include <iostream> #include <cmath> using namespace std; int main(){ double a, b, c; // Parmetros de la ecuacin double raiz1, raiz2; // Races obtenidas double radical, denominador; cout << "\nIntroduce coeficiente de 2o grado: "; cin >> a; cout << "\nIntroduce coeficiente de 1er grado: "; cin >> b; cout << "\nIntroduce coeficiente independiente: "; cin >> c; denominador = 2*a; radical = sqrt( b*b-4*a*c ); raiz1 = (-b + radical) / denominador; raiz2 = (-b - radical) / denominador; cout << "\nLas races son" << raiz1 << " y " << raiz2; }

Introduccin a la Programacin Tipos de datos comunes en C++ Operando con tipos numricos distintos

66

I.5.4.
I.5.4.1.

Operando con tipos numricos distintos


Usando enteros y reales en una misma expresin

Muchos operadores numricos permiten como argumentos, expresiones de tipos distintos.

5.0 5.0 5 / 5.0

* 7.0 / 7.0 7 / 7

Devuelve Devuelve Devuelve Devuelve

35.0 0.7142857 0 0.7142857

Recordad que para evaluar el resultado de una expresin que contenga datos con tipos distintos, el compilador usar el tipo adecuado que sea capaz de albergar el resultado. Por ejemplo, usar un double para almacenar el resultado de 5.0 / 7, es decir, 0.7142857. El operador de asignacin tambin permite trabajar con tipos distintos.

double real; int entero = 5; real = 5; // double = int real = entero; // double = int
Internamente se produce una transformacin de tipo (casting) del valor 5 (en su representacin como un int) al valor 5.0 (en su representacin como un double)

Introduccin a la Programacin Tipos de datos comunes en C++ Operando con tipos numricos distintos

67

double real; real = 5.0 / 7; // // real = 5 / 7; // //

double Asigna double Asigna

= a = a

double real el valor 0.7142857 int real el valor 0.0

Muy importante: Primero se evala la expresin en la parte derecha de la asignacin y luego se realiza la asignacin.

int edad1 = 10, edad2 = 5; double media; media = (edad1 + edad2)/2; // :-(
asigna a media el valor 7.0. Es un error lgico, difcil a veces de detectar. Posible solucin: Declarar edad1 y edad2 como double? El resultado sera 7.5, pero no debemos cambiar el tipo asociado a la edad, pues su semntica es de un entero. Forzaremos la divisin real usando un literal real en un operando.

int edad1 = 10, edad2 = 5; double media; media = (edad1 + edad2)/2.0; // :-)

Introduccin a la Programacin Tipos de datos comunes en C++ Operando con tipos numricos distintos

68

Qu pasa cuando asignamos un real a un entero? Simplemente, se pierde la parte decimal, es decir, se trunca.

double real; int entera; real = 5.7; entera = real // Asigna a entera el valor 5
Este truncamiento tambin ocurre si ejecutamos

cin >> entera;


e introducimos un valor real.

Estudiar: Un caso especial es el casting a entero de un double que contenga innito o indeterminacin. El resultado es un valor impredecible.

int entero, denominador; double real; denominador = 0; real = 17/(denominador*1.0); entero = real; real = 0/(denominador*1.0); entero = real; entero = 17/denominador;

// // // // //

Almacena INF Almacena basura Almacena NaN Almacena basura Error ejecucin Por qu?

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato carcter

69

I.5.5.
I.5.5.1.

El tipo de dato carcter


Rango

El rango de un dato de tipo carcter (char) es un conjunto nito y ordenado de caracteres: letras minsculas, maysculas, dgitos del 0 al 9 y otros caracteres especiales. Hay varios tipos de dato de carcter: char, wchar, signed char, etc. En FP usaremos char.

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato carcter

70

Cdigo ASCII extendido (256 caracteres) Cada carcter tiene asociado un nmero de orden (entre 0 y 255)

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato carcter

71

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato carcter

72

Literales de carcter Son tokens formados por: Un nico carcter encerrado entre comillas simples: '!' 'A' 'a' '5' '' Observad que '5' es un literal de carcter y 5 es un literal entero Cuidado!: 'cinco' o '11' no son literales de carcter. O bien una secuencia de escape, es decir, el smbolo \ seguido de otro smbolo, como por ejemplo: Secuencia Signicado

\n \t \b \r \f \' \" \\

Nueva lnea (retorno e inicio) Tabulador Retrocede 1 carcter Retorno de carro Salto de pgina Comilla simple Comilla doble Barra inclinada

Las secuencias de escape tambin deben ir entre comillas simples, por ejemplo, '\n', '\t', etc.

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato carcter

73

#include <iostream> using namespace std; int main(){ const char NUEVA_LINEA = '\n'; char letra_piso; letra_piso = 'B'; // Almacena 'B' cout << letra_piso << "ienvenidos"; cout << '\n' << "Empiezo a escribir en la siguiente lnea"; cout << '\n' << '\t' << "Acabo de tabular esta lnea"; cout << NUEVA_LINEA; cout << '\n' << "Esto es una comilla simple: " << '\''; }
Escribira en pantalla:

Bienvenidos Empiezo a escribir en la siguiente lnea Acabo de tabular esta lnea Esto es una comilla simple: '
Nota. Para escribir un retorno de carro, tambin puede usarse una constante llamada endl en la forma: cout << endl << "Adis" << endl

Observad la diferencia:

double r; char letra; letra = 'r'; r = 23; // literal de carcter 'r' // variable real r

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato carcter

74

I.5.5.2.

Funciones estndar

El chero de cabecera cctype contiene varias funciones relativas a caracteres. Por ejemplo:

tolower #include <cctype> using namespace std; int main(){ char letra_piso; letra_piso = tolower('A'); letra_piso = toupper('A'); letra_piso = tolower('B'); letra_piso = tolower('?'); ..................

toupper

// // // //

Almacena Almacena Almacena Almacena

'a' 'A' 'b' '?'

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato carcter

75

I.5.5.3.

El tipo char como un tipo entero

En C++, el tipo char es realmente un tipo entero pequeo . Cuando hacemos

char letra_piso; letra_piso = 'A';


estamos asignando a la variable letra_piso el nmero de orden en la tabla ASCII del carcter 'A', es decir, el 65.

char letra_piso; letra_piso = 'A';

// letra_piso contiene 65

De hecho, tambin podramos poner:

char letra_piso; letra_piso = 65;

// letra_piso contiene 65

Lo anterior es posible con cualquier tipo entero:

int letra_piso; letra_piso = 'A'; letra_piso = 65; letra_piso = '7'; letra_piso = 7;

// // // //

Almacena Almacena Almacena Almacena

65 65 55 7

As pues, el tipo char es un entero pequeo ya que est pensado para albergar los nmeros de rdenes de la tabla ASCII (entre 0 y 255)

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato carcter

76

Veamos algunas consecuencias: Podemos operar con los caracteres como si fuesen nmeros:

char letra_piso; letra_piso = 'A'+1; letra_piso = 65+1; letra_piso = '7'-1; letra_piso = 'A' + '7';

// // // // //

Tambin valdra int letra_piso; Almacena 66 = 'B' Almacena 66 = 'B' Almacena 54 = '6' Almacena 120

Tambin podemos usar el operador - con dos argumentos de carcter. Devuelve un entero:

int orden; orden = 'c' - 'a' // Almacena 2

El recurso cout se ha programado de la siguiente forma: Si se pasa a cout un literal o variable de tipo char, imprime el carcter correspondiente al entero almacenado. Si se pasa a cout un literal o variable de tipo entero (distinto a char), imprime el entero almacenado. Qu imprimira la sentencia cout << 'A'+1? No imprime 'B' como cabra esperar sino 66 ya que 1 es un literal entero y por tanto de tipo int. El tipo int es ms grande que el tipo char, por lo que 'A'+1 es una expresin de tipo int.

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato carcter

77

Estudiar: C++ ofrece un amplio repertorio de tipos de datos para representar, por ejemplo, enteros slo positivos, reales muy grandes, etc. Consultad

http://www.zator.com/Cpp/E2_2_3.htm http://www.cplusplus.com/doc/tutorial/variables/

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato cadena de caracteres

78

I.5.6.

El tipo de dato cadena de caracteres

Un literal de tipo cadena de caracteres (string) es una sucesin de caracteres encerrados entre comillas dobles: "Hola", "a" son literales de cadena de caracteres

cout << "Esto es un literal de cadena de caracteres";


Las secuencias de escape tambin pueden aparecer en los literales de cadena de caracteres presentes en cout

int main(){ cout << "Bienvenidos"; cout << "\nEmpiezo a escribir en la siguiente lnea"; cout << "\n\tAcabo de tabular esta lnea"; cout << "\n"; cout << "\nEsto es una comilla simple '"; cout << " y esto es una comilla doble \""; }
Escribira en pantalla:

Bienvenidos Empiezo a escribir en la siguiente lnea Acabo de tabular esta lnea Esto es una comilla simple ' y esto es una comilla doble "

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato cadena de caracteres

79

Ejercicio. Determinar cuales de las siguientes son constantes de cadena de caracteres vlidas, y determinar la salida que tendra si se pasase como argumento a cout a) "8:15 P.M." b) "'8:15 P.M." c) '"8:15 P.M."' f) "Direccin\'n"

d) "Direccin\n" e) "Direccin'n" g) "Direccin\\'n"

C++ ofrece dos alternativas para trabajar con cadenas de caracteres: Cadenas estilo C: son vectores de caracteres con terminador '\0'. Se ver en la asignatura Metodologa de la Programacin. Usando el tipo string (la recomendada en esta asignatura)

int main(){ string mensaje_bienvenida; mensaje_bienvenida = "\tFundamentos de Programacin\n"; cout << mensaje_bienvenida; }
Para poder operar con un string debemos incluir la biblioteca string:

#include <iostream> #include <string> using namespace std; int main(){ string cad; cad = "Hola y "; cad = cad + "adis"; cout << cad; }

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato cadena de caracteres

80

Realmente, string es una clase (lo veremos en temas posteriores) por lo que le sern aplicables mtodos en la forma:

cad = "Hola y "; cad.append("adis");


'

// :-O
$

&

La lectura de un string con cin es complicada cuando la cadena contiene separadores (espacios en blanco, tabuladores, etc). Por lo tanto, en esta asignatura, asumiremos que las cadenas ledas con cin no contienen separadores.

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato lgico o booleano

81

I.5.7.

El tipo de dato lgico o booleano

Es un tipo de dato muy comn en los lenguajes de programacin que se utiliza para representar los valores verdadero y falso que suelen estar asociados a una condicin. En C++ se usa el tipo bool. I.5.7.1. Rango

El rango de un dato de tipo lgico (boolean) est formado solamente por dos valores: verdadero y falso. Para representarlos, se usan los siguientes literales:

true

false

Una expresin lgica es una expresin cuyo resultado es un tipo de dato lgico. I.5.7.2. Operadores

Son los operadores clsicos de la lgica Y, O, NO que en C++ son los operadores &&, ||, ! respectivamente.

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato lgico o booleano

82

p Carlos es varn q Carlos es joven p true true q true p && q p || q true true true true false true false

!p
false true

false false false

false true

false false false Por ejemplo: Si p es false, y q es true, p && q ser false p || q ser true Recordad:

false && expresin true || expresin

siempre es false. siempre es true.

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato lgico o booleano

83

Muchas funciones de cctpye devuelven un valor lgico

isalpha
Por ejemplo,

isalnum

isdigit

...

isalpha('3')
es una expresin lgica (devuelve false)

/* Ejemplo de tipo de dato lgico (bool) #include <cctype> using namespace std;

*/

int main() { bool es_alfa, es_alfanum, es_digito_numerico; bool compuesto; es_alfa = isalpha('3'); // Asigna false a es_alfa es_alfanum = isalnum('3'); // Asigna true a es_alfanum es_digito_numerico = isdigit('3'); // Asigna true a es_digito_numerico compuesto = (es_alfa && es_alfanum); compuesto = (es_alfa || es_alfanum); compuesto = !es_alfa; ....... } // Resultado: false // Resultado: true // Resultado: true

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato lgico o booleano

84

I.5.7.3.

Operadores Relacionales

Son los operadores habituales de comparacin de expresiones numricas. Pueden aplicarse a operandos tanto enteros, reales, como de caracteres y tienen el mismo sentido que en Matemticas. El resultado es de tipo bool.

== (igual), != (distinto), <, >, <= (menor o igual) y >= (mayor o igual)
Algunos ejemplos: La expresin (4 < 5) devuelve valor true La expresin (4 > 5) devuelve el valor false La relacin de orden entre caracteres se establece segn la tabla ASCII. La expresin ('a' > 'b') devuelve el valor false.

!= es el operador relacional distinto. ! es la negacin lgica. == es el operador relacional de igualdad. = es la operacin de asignacin.
Tanto en == como en != se usan 2 signos para un nico operador

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato lgico o booleano

85

//

Ejemplo de operadores relacionales

int main(){ int entero1 = 3, entero2 = 5; double real1, real2; bool menor, iguales; menor = menor = menor = real1 = real2 = menor = menor = iguales }
Veremos su uso en la sentencia condicional:

entero1 < entero2; entero2 < entero1; (entero1 < entero2) && !(entero2 < 7); 3.8; 8.1; real1 > entero1; !menor && (real1 > real2); = real1 == real2;

if (4 < 5) cout << "4 es menor que 5"; if (!(4 > 5)) cout << "4 es menor o igual que 5";

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo de dato lgico o booleano

86

Reglas de Precedencia:

() ! < <= > >= == != && ||


A es menor o igual que B y B no es mayor que C

int A = 40, B = 34, C = 50; bool condicion; condicion = A <= B && !B > C; condicion = (A <= B) && (!(B > C)); condicion = (A <= B) && !(B > C); condicion = (A <= B) && (B <= C);


// // // //

MAL BIEN Recomendado Mucho mejor




Consejo:


Simplicad las expresiones lgicas, para as aumentar su legibilidad.

Ejercicio. Escribid una expresin lgica que devuelva true si un nmero entero edad est en el intervalo [0,100]

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo enumerado

87

I.5.8.

El tipo enumerado

Supongamos un programa de contabilidad en el que queremos representar tres posibles valores de desgravacin, a saber 7, 16 y 30 %. Alternativas: Usar una nica variable desgravacion

int desgravacion; desgravacion = 7; ......


Propenso a errores: podemos poner por error el literal 17, que es aceptado en un int. Usar tres constantes:

const int desgravacion_7 = 7; const int desgravacion_16 = 16; const int desgravacion_33 = 33;
Tedioso, pues siempre tendremos que manejar tres variables

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo enumerado

88

Usar un tipo enumerado (enumerated type) . Es un tipo entero que slo acepta unos valores concretos especicados por el programador.

double salario; enum TipoDesgravacion {baja=7, media=16, alta=33}; TipoDesgravacion desgravacion; cout << baja; // Imprime 7 desgravacion = baja; // Almacena internamente 7 cin >> salario; salario = salario - salario*desgravacion/100.0; desgravacion = 5; cin >> desgravacion;
#

// Error compilacin :-) // Error compilacin :-)

"

Si a una constante slo se le puede asignar un nico valor, a un tipo enumerado slo se le puede asignar un nmero muy limitado de valores.

Ampliacin:
Si no se pone ningn valor en la denicin del tipo, C++ le asigna a cada valor del enumerado el siguiente entero del asignado al valor anterior. Al primero le asigna el cero.

enum TipoPocoUsual {baja, media, alta=4, muy_alta}; TipoPocoUsual raro; raro = baja; cout << raro; // 0 cout << media; // 1 cout << alta; // 4 cout << muy_alta; // 5

Introduccin a la Programacin Tipos de datos comunes en C++ El tipo enumerado

89

Bibliografa recomendada para este tema: A un nivel menor del presentado en las transparencias: Primer captulo de Deitel & Deitel Primer captulo de Garrido. A un nivel similar al presentado en las transparencias: Captulo 1 y apartados 2.1, 2.2 y 2.3 de Savitch A un nivel con ms detalles: Los tres primeros captulos de Stephen Prata. Los dos primeros captulos de Lafore.

Tema II

Estructuras de Control
Objetivos: Introducir las estructuras condicionales que nos permitirn realizar saltos hacia adelante durante la ejecucin del cdigo. Introducir las estructuras repetitivas que nos permitirn realizar saltos hacia atrs durante la ejecucin del cdigo. Introducir pautas de programacin en la construccin de las estructuras condicionales y repetitivas.

Autor: Juan Carlos Cubero. Sugerencias: por favor, enviar un e-mail a JC.Cubero@decsai.ugr.es

Estructuras de Control Estructura condicional

91

II.1.

Estructura condicional
Secuencial Estructuras Condicional Repetitiva

Estructura secuencial (sequential control ow structure) : las instrucciones se van ejecutando sucesivamente, siguiendo el orden de aparicin de stas. No hay saltos. Una condicin (condition) es una expresin lgica. Una estructura condicional (conditional structure) es una estructura que permite la ejecucin de una (o ms) sentencia(s) dependiendo de la evaluacin de una condicin. Tambin se les denomina sentencia condicional (conditional statement) ya que todo el bloque de la estructura forma una sentencia. Existen tres tipos: Simple, Doble y Mltiple.

Estructuras de Control Estructura condicional Estructura condicional simple

92

II.1.1.

Estructura condicional simple


if (<condicin>)
<bloque if>

<condicin> es una expresin lgica <bloque if> es el bloque que se ejecutar si la expresin lgica se evala a true. Si hay varias sentencias dentro, es necesario encerrarlas entre llaves. Si slo hay una sentencia, pueden omitirse las llaves. Los parntesis que encierran la condicin son obligatorios. Ejemplo. Leer la edad de una persona e imprimir "Es mayor de edad" en el caso de que su edad sea mayor o igual que 18.

int edad; cin >> edad; if (edad >= 18){ cout << "\nEs mayor de edad"; } cout << "\nFn del programa";
o si se preere:

if (edad >= 18) cout << "\nEs mayor de edad"; cout << "\nFn del programa";

Estructuras de Control Estructura condicional Estructura condicional simple

93

En el ejemplo anterior podramos usar una variable lgica adicional:

int edad; bool es_mayor_de_edad; cin >> edad; es_mayor_de_edad = (edad >= 18); if (es_mayor_edad == true) cout << "\nEs mayor de edad"; cout << "\nFn del programa";
Observad que la estructura condicional equivale a la siguiente:

if (es_mayor_edad) cout << "\nEs mayor de edad";


sta ltima es ms fcil de leer. Observad tambin que

if (es_mayor_edad==false) cout << "\nEs menor de edad";


equivale a

if (!es_mayor_edad) cout << "\nEs menor de edad";

Estructuras de Control Estructura condicional Estructura condicional simple '

94 $

Consejo:

&

No usad comparaciones del if (expresin_lgica == true) en las tructuras condicionales. Sustituirlas if (expresin_lgica)

tipo espor
%

Estructuras de Control Estructura condicional Estructura condicional simple

95

Recordad el ejemplo de la pgina 65:

#include <iostream> #include <cmath> using namespace std; int main(){ double a, b, c; // Parmetros de la ecuacin double raiz1, raiz2; // Races obtenidas double radical, denominador; 1 2 3 4 5 6 7 8 9 10 cout << "\nIntroduce coeficiente de 2o grado: "; cin >> a; cout << "\nIntroduce coeficiente de 1er grado: "; cin >> b; cout << "\nIntroduce coeficiente independiente: "; cin >> c; denominador = 2*a; radical = sqrt( b*b-4*a*c ); raiz1 = (-b + radical) / denominador; raiz2 = (-b - radical) / denominador;

11 cout << "\nLas races son" << raiz1 << " y " << raiz2; }
Flujo de control: (1,2,3,4,5,6,7,8,9,10,11).

Estructuras de Control Estructura condicional Estructura condicional simple

96

Es a distinto de cero? Si. Entonces sigue la ejecucin. No. Entonces salta las sentencias 711 y termina.

#include <iostream> #include <cmath> using namespace std; int main(){ double a, b, c; // Parmetros de la ecuacin double raiz1, raiz2; // Races obtenidas double radical, denominador; cout << "\nIntroduce coeficiente de 2o grado: "; cin >> a; cout << "\nIntroduce coeficiente de 1er grado: "; cin >> b; cout << "\nIntroduce coeficiente independiente: "; cin >> c; if (a!=0) { denominador = 2*a; radical = sqrt( b*b-4*a*c ); raiz1 = (-b + radical) / denominador; raiz2 = (-b - radical) / denominador; cout << "\nLas races son" << raiz1 << " y " << raiz2; } }

Estructuras de Control Estructura condicional Estructura condicional simple

97

El compilador se salta todos los separadores (espacios, tabulaciones, etc) entre las sentencias delimitadas por ;. Pero para favorecer la lectura del cdigo y enfatizar el bloque de sentencias incluidas en la estructura condicional, usaremos el siguiente estilo de codicacin:
cin >> c;

if (a!=0){ denominador = 2*a; radical = sqrt( b*b-4*a*c ); raiz1 = (-b + radical) denominador; raiz2 = (-b - radical) denominador; (

Lnea en blanco antes del condicional

co!t "" #$n%as ra&ces son# "" raiz1 "" # ' # "" raiz2;

Lnea en blanco despus del del condicional Bloque if tabulado 3 espacios Llave cerrada (sin tabulacin)

Destacad visualmente el bloque de instrucciones de una estructura condicional. No seguir estas normas baja puntos en el examen.

Estructuras de Control Estructura condicional Estructura condicional simple

98

Una notacin para describir algoritmos: Diagramas de ujo (owchart) Smbolos bsicos
INICIO Simbolo terminal Estructura secuencial

<CONDICION> Operacion de E/S

true FIN Delimitadores

false

Direccion del flujo

Bifurcador de flujo

Estructuras de Control Estructura condicional Estructura condicional simple

99

Ejemplo. Races de una ecuacin de segundo grado


Inicio

cout << "\nIntroduce coeficiente de 2 grado: "

cin >> a

cout << "\nIntroduce coeficiente de 1er grado: "

cin >> b

cout << "\nIntroduce coeficiente independiente: "

cin >> c

false

a != 0

true

denominador = 2*a

radical = s rt! b*b"#*a*c $

rai%1 = !"b & radical$ ' denominador

rai%2 = !"b " radical$ ' denominador

(in

Estructuras de Control Estructura condicional Estructura condicional simple

100

Ejemplo. Comprobad si un contribuyente es menor de edad o es mayor de 65, pero en cualquier caso con unos ingresos menores a 40000

int edad, ingresos; edad = 20; ingresos = 23000; if (edad < 18 || edad >= 65 && ingresos < 40000) // :-( cout << "\nContribuyente de especial tratamiento";
Cuidado con la precedencia de operadores. Debemos poner:

if ( (edad < 18 || edad >= 65) && ingresos < 40000) // :-) cout << "\nContribuyente de especial tratamiento";

Estructuras de Control Estructura condicional Estructura condicional simple

101

Si hay varias sentencias, es necesario encerrarlas entre llaves. Dicho de otra forma: si no ponemos llaves, el compilador entiende que la nica sentencia del bloque if es la que hay justo debajo.

if (a!=0) denominador = 2*a; radical = sqrt( b*b-4*a*c ); raiz1 = (-b + radical) / denominador; raiz2 = (-b - radical) / denominador; cout << "\nLas races son" << raiz1 << " y " << raiz2;
Para el compilador es como si fuese:

if (a!=0){ denominador = 2*a; } radical = sqrt( b*b-4*a*c ); raiz1 = (-b + radical) / denominador; raiz2 = (-b - radical) / denominador; cout << "\nLas races son" << raiz1 << " y " << raiz2;

Estructuras de Control Estructura condicional Estructura condicional simple

102

Ejemplo.

if (edad >= 18) cout << "\nEs mayor de edad"; cout << "\nFn del programa";
Y si la edad es menor de 18?

if (edad >= 18) cout << "\nEs mayor de edad"; if (edad < 18) cout << "\nEs menor de edad"; cout << "\nFn del programa";
La solucin propuesta funciona pero, aunque no lo parezca, se repite cdigo ya que se evalan condiciones mutuamente excluyentes: si la expresin edad >= 18 es true, la expresin edad < 18 siempre es false y viceversa. De hecho:

edad < 18

es equivalente a

!(edad >= 18)

if (edad >= 18) cout << "\nEs mayor de edad"; if (!(edad >= 18)) cout << "\nEs menor de edad";
Ahora se observa mejor que estamos repitiendo cdigo, violando por tanto el principio de una nica vez. Lo resolvemos usando un condicional doble.

Estructuras de Control Estructura condicional Condicional doble

103

II.1.2.

Condicional doble
if <condicin>
<bloque if>;

else
<bloque else>;

false <condicin>

true

bloque else

bloque if

int edad; cin >> edad; if (edad >= 18) cout << "\nEs mayor de edad"; else cout << "\nEs menor de edad"; cout << "\nFn del programa";

Estructuras de Control Estructura condicional Condicional doble

104

Qu pasa si a = 0 en la ecuacin de segundo grado? El algoritmo debe devolver c/b. Podemos hacer lo siguiente:

if (a!=0){ denominador = 2*a; radical = sqrt( b*b-4*a*c ); raiz1 = (-b + radical) / denominador; raiz2 = (-b - radical) / denominador; cout << "\nLas races son" << raiz1 << " y " << raiz2; } if (a==0) cout << "\nTiene una nica raz" << -c/b;
Pero estamos usando dos condiciones mutuamente excluyentes: (a!=0) y (a==0). Lo resolvemos usando un condicional doble.

Estructuras de Control Estructura condicional Condicional doble

105

#include <iostream> #include <cmath> using namespace std; int main(){ double a, b, c; // Parmetros de la ecuacin double raiz1, raiz2; // Races obtenidas double radical, denominador; cout << "\nIntroduce coeficiente de 2o grado: "; cin >> a; cout << "\nIntroduce coeficiente de 1er grado: "; cin >> b; cout << "\nIntroduce coeficiente independiente: "; cin >> c; if (a!=0) { denominador = 2*a; radical = sqrt( b*b-4*a*c ); raiz1 = (-b + radical) / denominador; raiz2 = (-b - radical) / denominador; cout << "\nLas races son" << raiz1 << " y " << raiz2; } else{ raiz1 = -c/b; cout << "\nLa nica raz es " << raiz1; } }

Estructuras de Control Estructura condicional Condicional doble

106

Inicio

cout << "\nIntroduce coeficiente de 2 grado: "

cin >> a

cout << "\nIntroduce coeficiente de 1er grado: "

cin >> b

cout << "\nIntroduce coeficiente independiente: "

cin >> c

false

a != 0

true

denominador = 2*a

rai%1 = "c ' b

radical = s rt! b*b"#*a*c $

cout << "\n)a *nica ra+% ,,,

rai%1 = !"b & radical$ ' denominador

rai%2 = !"b " radical$ ' denominador

(in

Estructuras de Control Estructura condicional Condicional doble

107

Ejemplo. Calculad el mayor de dos valores a y b.

cin >> a; cin >> b; if (a >= b) max = a; else max = b; cout << "\nEl mayor es " << max;
Ejemplo. El mayor de tres nmeros a, b y c (primera aproximacin). Algoritmo: Entradas: a, b y c Salidas: El mayor entre a, b y c Descripcin:

Si a es mayor que los otros, el mayor es a Si b es mayor que los otros, el mayor es b Si c es mayor que los otros, el mayor es c
Implementacin:

if ((a>=b) && (a>=c)) max = a; if ((b>=a) && (b>=c)) max = b; if ((c>=a) && (c>=b)) max = c;

Estructuras de Control Estructura condicional Condicional doble

108

(a>=b) y (a>=c)
false

true

max = a

(b>=a) y (b>=c)
false

true

max = b

(c>=a) y (c>=b)
false

true

max = c

cout << max

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

109

II.1.3.

Anidamiento de estructuras condicionales

Dentro de un bloque if (else), puede incluirse otra estructura condicional, anidndose tanto como permita el compilador. Cundo se ejecuta cada instruccin?

if (condic_1) { inst_1; if (condic_2) { inst_2; } else { inst_3; } inst_4; } else { inst_5; } inst_1 inst_2 inst_3 inst_4 inst_5

condic_1
true true true true false

condic_2
independiente true false independiente independiente

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

110

Ejemplo. El mayor de tres nmeros (segunda aproximacin) Algoritmo: Entradas y Salidas: idem Descripcin:

Si a es mayor que b, entonces Calcular el mximo entre a y c En otro caso, Calcular el mximo entre b y c
Implementacin:

if (a>=b) if (a>=c) max = a; else max = c; else if (b>=c) max = b; else max = c;

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

111

true

a>=b

false

true

a>=c

false

true

b>=c

false

max = a

max = c

max = b

max = c

cout << max

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

112

Ejemplo. El mayor de tres nmeros (tercera aproximacin) Algoritmo: Entradas y Salidas: idem Descripcin e Implementacin:

/* Calcular el mximo (max) entre a y b. Calcular el mximo entre max y c. */ if (a>=b) max = a; else max = b; if (c>max) max = c;

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

113

false

a>=b

true

max = b

max = a

c>max false

true

max = c

cout << max

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

114

Con qu algoritmo nos quedamos? Supongamos que todos los valores son distintos La solucin 1 siempre evala 3 condiciones y realiza 1 asignacin. La solucin 2 siempre evala 2 condiciones y realiza 1 asignacin. La solucin 3 siempre evala 2 condiciones y realiza 1 2 asignaciones. La solucin 2 realiza alguna evaluacin menos, pero la solucin 3 es muchsimo mejor: Es mucho ms fcil de entender No repite cdigo Es mucho ms fcil de extender a varios valores.

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

115

El mayor de cuatro nmeros con la segunda aproximacin:

if (a>=b) if (a>=c) if (a>=d) max = a; else max = d; else if (c>=d) max = c; else max = d; else if (b>=c) if (b>=d) max = b; else max = d; else if (c>=d) max = c; else max = d;

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

116

El mayor de cuatro nmeros con la tercera aproximacin: Algoritmo: Entradas y Salidas: idem Descripcin e Implementacin:

/* Calcular el mximo (max) entre a y b. Calcular el mximo entre max y c. Calcular el mximo entre max y d. */ if (a>=b) max = a; else max = b; if (c>max) max = c; if (d>max) max = d;
En general:

Calcular el mximo (max) entre a y b. Para cada uno de los valores restantes, calcular el mximo entre max y dicho valor.

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

117

Ejemplo. Men de operaciones.

// Programa que permite operar con dos nmeros enteros #include <iostream> using namespace std; int main(){ int dato1, dato2, resultado; char opcion; cout << "\nIntroduce el primer operando: "; cin >> dato1; cout << "\nIntroduce el segundo operando: "; cin >> dato2; cout << "\nElija (S)Sumar, (R)Restar, (M)Multiplicar: "; cin >> opcion; if (opcion cout << if (opcion cout << if (opcion cout << if (opcion cout << } == 'S') "\nSuma = " << dato1+dato2; == 'R') "\nResta = " << dato1-dato2; == 'M') "\nMultiplicacin = " << dato1*dato2; != 'R' && opcion != 'S' && opcion != 'M') "\nNinguna operacin";

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

118

Ejemplo. Men de operaciones (continuacin) Lo hacemos ms ecientemente:

if (opcion == 'S') cout << "\nSuma = " << dato1+dato2; else if (opcion == 'R') cout << "\nResta = " << dato1-dato2; else if (opcion == 'M') cout << "\nMultiplicacin = " << dato1*dato2; else cout << "\nNinguna operacin";

Una forma tambin vlida de tabular:

if (opcion == 'S') cout << "\nSuma = " << dato1+dato2; else if (opcion == 'R') cout << "\nResta = " << dato1-dato2; else if (opcion == 'M') cout << "\nMultiplicacin = " << dato1*dato2; else cout << "\nNinguna operacin"; }

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

119

Cmo describimos un algoritmo? Descripcin de un algoritmo: Se trata de describir la idea principal del algoritmo, de forma concisa y esquemtica, sin entrar en detalles innecesarios.

if (a>=b) max = a; else max = b; if (c>max) max = c;


Una lamentable descripcin del algoritmo: Compruebo si a>=b. En ese caso, lo que hago es asignarle a la variable max el valor a y si no le asigno el otro valor, b. Una vez hecho esto, paso a comprobar si el otro valor, es decir, c, es mayor que max (la variable anterior), en cuyo caso le asigno a max el valor c y si no, no hago nada. El colmo: Compruevo si a>=b y en ese caso lo que ago es asignarle a la variable max el valor a y sino le asigno el otro valor b una vez echo esto paso a comprovar si el otro valor es decir c es mayor que max (la variable anterior) en cuyo caso le asigno a max el valor c y sino no ago nada

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

120

Nunca parafrasearemos el cdigo

/* Si a es >= b, asignamos a max el valor a En otro caso, le asignamos b. Una vez hecho lo anterior, vemos si c es mayor que max, en cuyo caso le asignamos c */ if (a>=b) max = a; else max = b; if (c>max) max = c;
Seremos esquemticos (pocas palabras en cada lnea)

/* Calcular el mximo entre a y b, y una vez hecho esto, pasamos a calcular el mximo entre el anterior, al que llamaremos max, y el nuevo valor c */ /* Calcular el mximo (max) entre a y b. Calcular el mximo entre max y c. */

Estructuras de Control Estructura condicional Anidamiento de estructuras condicionales

121

Comentaremos un bloque completo La descripcin del algoritmo la incluiremos antes de un bloque, pero nunca entre las lneas del cdigo. Esto nos permite separar las dos partes y poder leerlas independientemente.

// Calcular el mximo entre a y b if (a>=b) max = a; else // En otro caso: max = b; // Calcular el mximo entre max y c if (c>max) max = c;
Algunos autores incluyen la descripcin a la derecha del cdigo, pero es mucho ms difcil de mantener (si incluimos lneas de cdigo nuevas, se descompone todo el comentario):

if (a>=b) if (a>=c) max = a; else max = c;

// // // //

La descripcin del comentario es correcta pero no el sitio (a la derecha de cada lnea) Calcular el mximo entre a y c Calcular el mximo entre max y c

Usad descripciones de algoritmos que sean concisas con una presentacin visual agradable y esquemtica. Las descripciones han de ser sobre un bloque completo. Slo se usarn comentarios al nal de una lnea en casos puntuales, para aclarar el cdigo de dicha lnea. No seguir estas normas baja puntos en el examen.

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

122

II.1.4.

Construccin de estructuras condicionales


Separacin de entradas/salidas y cmputos

II.1.4.1.

Cualquier programa medianamente complejo contiene miles de lneas de cdigo escritas por varios equipos de programadores especialistas en facetas distintas. En un tema posterior veremos que los bloques de cdigo se agruparn en funciones, clases, bibliotecas, etc. Como mnimo habr un equipo especialista en la interfaz de usuario (entradas y salidas de datos E/S). Para poder aislar los bloques de cdigo correspondientes a las E/S, impondremos que si dentro de un bloque realizamos alguna operacin de E/S, en dicho bloque no realizaremos ningn cmputo propio del programa.
Interfaz de usuario consulta Cmputos

resultados

En nuestros programas la interfaz de usuario es muy sencilla y se basa en las rdenes cin y cout. An as, como buenos programadores, separaremos los bloques de E/S de los cmputos. Para ello, usaremos variables que indiquen lo que ha ocurrido en un bloque.

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

123

Ventajas de la separacin de E/S y cmputos: Se separan responsabilidades. Cada equipo de desarrollo puede actualizar su parte, sin afectar al resto. Se favorece la reutilizacin entre plataformas (Linux, Windows, etc). Si en un bloque usamos cout por ejemplo, dicho bloque slo funcionar en una ventana de consola y no en una ventana tpica de Windows.

int edad; cin >> edad; if (edad >= 18) // <- Cmputo cout << "\nEs mayor de edad"; // <- E/S
Para separar E/S es_mayor_edad: de cmputos introducimos la variable

int edad; bool es_mayor_edad; // Entrada de datos: cin >> edad; // Cmputos: es_mayor_edad = (edad>18); // Salida de resultados: if (es_mayor_edad) cout << "\nEs mayor de edad";
Esto me permite reutilizar el cdigo es_mayor_edad = (edad>18); en otros sitios:

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

124

es_mayor_edad = (edad>18); if (es_mayor_edad) System::Windows::Forms::MessageBox::Show("Es mayor de edad");

Los bloques que realizan entradas o salidas de datos (cin, cout) estarn separados de los bloques que realizan cmputos.

Ampliacin:
Los bloques de cdigo de entradas de datos, salida de resultados, cmputos, etc se aslan en lo que se denominan capas (layers) . Adems, cada una de estas capas puede ejecutarse en distintos sitios fsicos o niveles (tiers) (como en el ejemplo de la bsqueda en la web)

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

125

Ejemplo. Men de operaciones.

if (opcion == 'S') cout << "\nSuma = " << dato1+dato2; else if (opcion == 'R') cout << "\nResta = " << dato1-dato2; else if (opcion == 'M') cout << "\nMultiplicacin = " << dato1*dato2; else cout << "\nNinguna operacin";
En un bloque usamos variables que almacenen resultados y en otro bloque las usamos o mostramos:

bool operacion_valida; int dato1, dato2, resultado; // Bloque de entrada de datos ........... // Bloque de cmputos operacion_valida = true; if (opcion == 'S') resultado = dato1+dato2; else if (opcion == 'R') resultado = dato1-dato2; else if (opcion == 'M') resultado = dato1*dato2; else operacion_valida = false;

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

126

// Bloque de salida de resultados if (operacion_valida){ if (opcion == 'S') cout << "\nSuma = "; else if (opcion == 'R') cout << "\nResta = "; else if (opcion == 'M') cout << "\nMultiplicacin = "; cout << resultado; } else cout << "\nNinguna operacin";
Somos conscientes que volvemos a evaluar las condiciones sobre la opcin, pero el benecio de separar E/S y cmputos es mayor. Adems, con un esfuerzo adicional, tambin podemos evitar la evaluacin doble de condiciones. El programa quedara nalmente as:

bool operacion_valida; int dato1, dato2, resultado; char opcion; string mensaje_a_imprimir; // Bloque de entrada de datos cout << "\nIntroduce el primer operando: "; cin >> dato1; cout << "\nIntroduce el segundo operando: "; cin >> dato2; cout << "\nSelecciona (S) sumar, (R) restar, (M) multiplicar: "; cin >> opcion;

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

127

// Bloque de cmputos operacion_valida = true; if (opcion == 'S'){ mensaje_a_imprimir = "\nSuma = "; resultado = dato1+dato2; } else if (opcion == 'R'){ mensaje_a_imprimir = "\nResta = "; resultado = dato1-dato2; } else if (opcion == 'M'){ mensaje_a_imprimir = "\nMultiplicacin = "; resultado = dato1*dato2; } else{ mensaje_a_imprimir = "\nNinguna operacin"; operacion_valida = false; } // Bloque de salida de resultados cout << mensaje_a_imprimir; if (operacion_valida) cout << resultado;
Ejercicio. Utilizad una variable lgica contribuyente_especial y reescribid el cdigo siguiente, separando E/S y cmputos:

if ( (edad<18 || edad>=65) && ingresos<40000) // :-) cout << "\nContribuyente de especial tratamiento";

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

128

II.1.4.2.

Anidar o no anidar?

Un ejemplo en el que es mejor anidar Ejemplo. Reescribid el siguiente ejemplo utilizando nicamente estructuras condicionales no anidadas:

if (A>B) if (B<=C) if (C!=D) <S1>; else <S2>; else <S3>; else <S4>;

if ((A>B) && (B<=C) && (C!=D)) <S1>; if ((A>B) && (B<=C) && (C==D)) <S2>; if ((A>B) && (B>C)) <S3>; if (A<=B) <S4>;
Preferimos el primero ya que realiza menos comprobaciones, y sobre todo porque no duplica cdigo (el de las condiciones) y es, por tanto, menos propenso a errores de escritura o ante posibles cambios futuros.

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

129

Un ejemplo en el que es mejor no anidar

if (c1 && c2) bloque_A else bloque_B

if (c1) if (c2) bloque_A else bloque_B else bloque_B bloque_A: bloque_B: c1 true c2 true (c1&&c2) false: c1 true y c2 false c1 false y c2 true c1 false y c2 false c1 true c2 true c1 true y c2 false o bien c1 false

Primer caso:

Segundo caso: bloque_A: bloque_B:

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

130

Son equivalentes. Elegimos la primera porque: Al aumentar el anidamiento se va perdiendo en legibilidad y concisin. Muy importante: la segunda opcin repite cdigo (bloque_B) y por tanto es ms propenso a errores de escritura o ante posibles cambios futuros.
' $

Los factores a tener en cuenta (entre otros) para anidar o no estructuras condicionales son: Que no se repita cdigo.
&

Que se aumente la legibilidad de ste.

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

131

II.1.4.3.

Simplicacin de expresiones: lgebra de Boole

Debemos intentar simplicar las expresiones lgicas, para que sean fciles de entender. Usaremos las leyes del lgebra de Boole, muy similares a las conocidas en Matemticas elementales como: (a + b) = a b a(b + c) = ab + ac

!(A || B) !(A && B) A && (B || C) A || (B && C)

equivale equivale equivale equivale

a a a a

!A !A (A (A

&& || && ||

!B !B B) || (A && C) B) && (A || C)

Nota. Las dos primeras (relativas a la negacin) se conocen como Leyes de Morgan. Las dos siguientes son la ley distributiva (de la conjuncin con respecto a la disyuncin y viceversa). Ampliacin:
Consultad:

http://es.wikipedia.org/wiki/Algebra_booleana http://serbal.pntic.mec.es/~cmunoz11/boole.pdf

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

132

Ejemplo. Es trabajador activo si su edad no est por debajo de 18 o por encima de 65.

bool es_activo; int edad; cin >> edad; es_activo = !(edad<18 || edad>65); if (es_activo) cout << "\nTrabajador en activo"; ......

Aplicando las leyes de Morgan:

!(edad<18 || edad>65) equivale a !(edad<18) && !(edad>65) equivale a (edad >= 18) && (edad <= 65)
Es ms fcil de entender el siguiente cdigo:

es_activo = (edad >= 18) && (edad <= 65); if (es_activo) cout << "\nTrabajador en activo";

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

133

Ejemplo. Es posible beneciario de ayudas si no es un trabajador activo. Adems, ya sea menor de 18 aos o mayor de 65, la unidad familiar a la que pertenezca no puede tener una base imponible mayor de 35000 euros.

bool beneficiario; ....... beneficiario = ((base_imponible <= 35000) && (edad < 18)) || ((base_imponible <= 35000) && (edad > 65));
Es mucho ms fcil de entender lo siguiente (aplicando la lay distributiva):

beneficiario = (base_imponible <= 35000) && ( edad < 18 || edad > 65 );


Adems, no repetimos cdigo (base_imponible <= 35000)

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

134

II.1.4.4.

Cuidado con la comparacin entre reales

La expresin 1.0e15 == (1.0/3.0)*3.0 podra evaluarse a false debido a la precisin nita para calcular (1.0/3.0) (0.333333333) Es ms:

double descuento_base, porcentaje; descuento_base = 0.1; porcentaje = descuento_base * 100; if (porcentaje == 10) // Podra evaluarse a false :-O cout << "Descuento del 10%"; ....
Recordad que la representacin en coma otante no es precisa y 0.1 ser internamente un valor prximo a 1, pero no exacto. Soluciones: Fomentar condiciones de desigualdad Mejor: Fijar un error de precisin y aceptar igualdad cuando la diferencia de las cantidades sea menor que dicho error.

double real1, real2; const double epsilon = 0.00001; if ((real1-real2) < epsilon) cout << "Son iguales";

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

135

Ampliacin:
Como no es lo mismo comparar si 0.000001 est cerca de 0.000002, que comparar si 130.001 est cerca de 130.002, el mtodo anterior hay que renarlo. Para ms informacin:

http://www.codeguru.com/forum/showthread.php?t=323835 http://www.cygnus-software.com:80/papers/comparingfloats/ comparingfloats.htm

Estructuras de Control Estructura condicional Construccin de estructuras condicionales

136

II.1.4.5.

Evaluacin en ciclo corto y en ciclo largo

Evaluacin en ciclo corto (Short-circuit evaluation) : El compilador optimiza la evaluacin de expresiones lgicas evaluando sus trminos de izquierda a derecha hasta que sabe el resultado de la expresin completa (lo que signica que puede dejar trminos sin evaluar). La mayora de los compiladores realizan este tipo de evaluacin por defecto. Evaluacin en ciclo largo (Eager evaluation) : El compilador evala todos los trminos de la expresin lgica para conocer el resultado de la expresin completa. Ejemplo.

if ( (a>0) && (b<0) && (c<1) ) ...


Supongamos a = -3. Ciclo largo: El compilador evala (innecesariamente) todas las expresiones lgicas Ciclo corto: El compilador evala slo la primera expresin lgica. Por lo tanto, pondremos primero aquellas condiciones que sean ms probables de evaluarse como false Nota. Lo mismo pasa cuando el operador es ||

Estructuras de Control Estructura condicional Estructura condicional mltiple

137

II.1.5.

Estructura condicional mltiple

Recordemos el ejemplo de lectura de dos enteros y una opcin de la pgina 126. Nos centramos en el bloque de cmputos:

operacion_valida = true; if (opcion == 'S'){ mensaje_a_imprimir = "\nSuma = "; resultado = dato1+dato2; } else if (opcion == 'R'){ mensaje_a_imprimir = "\nResta = "; resultado = dato1-dato2; } else if (opcion == 'M'){ mensaje_a_imprimir = "\nMultiplicacin = "; resultado = dato1*dato2; } else{ mensaje_a_imprimir = "\nNinguna operacin"; operacion_valida = false; }
Podemos reescribir este cdigo utilizando otra estructura alternativa.

Estructuras de Control Estructura condicional Estructura condicional mltiple

138

switch (<expresin>) { case <constante1>:


<sentencias1>

break; case <constante2>:


<sentencias2>

break;
......................... [default: <sentencias>] }

<expresin> es un expresin entera. <constante i> <constante2> es un literal entero.

switch slo comprueba la igualdad.


No debe haber dos cases con la misma <constante> en el mismo switch. Si esto ocurre, slo se ejecutan las sentencias del caso que aparezca primero. El identicador especial default permite incluir un caso por defecto, que se ejecutar si no se cumple ningn otro. Se suele colocar como el ltimo de los casos.

Estructuras de Control Estructura condicional Estructura condicional mltiple

139

operacion_valida = true; switch (opcion) { case 'S': mensaje_a_imprimir = "\nSuma = "; resultado = dato1+dato2; break; case 'R': mensaje_a_imprimir = "\nResta = "; resultado = dato1-dato2; break; case 'M': mensaje_a_imprimir = "\nMultiplicacin = "; resultado = dato1*dato2; break; default: mensaje_a_imprimir = "\nNinguna operacin"; operacion_valida = false; }

Estructuras de Control Estructura condicional Estructura condicional mltiple

140

El gran problema con la estructura switch es que el programador olvidar en ms de una ocasin, incluir la sentencia break. La nica ventaja es que se pueden realizar las mismas operaciones para un grupo determinado de constantes:

operacion_valida = true; switch (opcion) { case 's': case 'S': mensaje_a_imprimir = "\nSuma = "; resultado = dato1+dato2; break; case 'r': case 'R': mensaje_a_imprimir = "\nResta = "; resultado = dato1-dato2; break; case 'm': case 'M': mensaje_a_imprimir = "\nMultiplicacin = "; resultado = dato1*dato2; break; default: mensaje_a_imprimir = "\nNinguna operacin"; operacion_valida = false; }

Estructuras de Control Estructura condicional Estructura condicional mltiple

141

Pero para conseguir ese objetivo, la siguiente solucin sera mucho mejor:

cin >> opcion; opcion = toupper(opcion); operacion_valida = true; switch (opcion) { case 's': case 'S': mensaje_a_imprimir = "\nSuma = "; resultado = dato1+dato2; break; case 'r': case 'R': mensaje_a_imprimir = "\nResta = "; resultado = dato1-dato2; break; case 'm': case 'M': mensaje_a_imprimir = "\nMultiplicacin = "; resultado = dato1*dato2; break; default: mensaje_a_imprimir = "\nNinguna operacin"; operacion_valida = false; }
Y para no tener errores lgicos si se nos olvida incluir break, podemos volver a lo que ya sabemos:

cin >> opcion; opcion = toupper(opcion); operacion_valida = true; if (opcion == 'S'){

Estructuras de Control Estructura condicional Estructura condicional mltiple

142

mensaje_a_imprimir = "\nSuma = "; resultado = dato1+dato2; } else if (opcion == 'R'){ mensaje_a_imprimir = "\nResta = "; resultado = dato1-dato2; } else if (opcion == 'M'){ mensaje_a_imprimir = "\nMultiplicacin = "; resultado = dato1*dato2; } else{ mensaje_a_imprimir = "\nNinguna operacin"; operacion_valida = false; }
' $

Consejo:

&

Slo para C++ En la medida de lo posible, evitad el uso de la estructura switch por los errores lgicos producidos al olvidarnos incluir algn break

Estructuras de Control Estructuras repetitivas

143

II.2.

Estructuras repetitivas

Una estructura repetitiva (iteration/loop) (tambin conocidas como bucles, ciclos o lazos) permite la ejecucin de una secuencia de sentencias: o bien, hasta que se satisface una determinada condicin Bucle controlado por condicin (Condition-controlled loop) o bien, un nmero determinado de veces Bucle controlado por contador (Counter controlled loop)

II.2.1.

Bucles controlados por condicin: pre-test y post-test


Formato

II.2.1.1.

Pre-test

Post-test

while (<condicin>) {
<cuerpo bucle> }

do {
<cuerpo bucle> } while (<condicin>);

Funcionamiento: En ambos, se va ejecutando el cuerpo del bucle mientras la condicin sea verdad. En un bucle pre-test (pre-test loop) (while) se evala la condicin antes de entrar al bucle y luego (en su caso) se ejecuta el cuerpo. En un bucle post-test (post-test loop) (do while) primero se ejecuta el cuerpo y luego se evala la condicin.

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

144

Cada vez que se ejecuta el cuerpo del bucle diremos que se ha producido una iteracin (iteration)

(Pretest)

(Posttest)

false

<cuerpo bucle> <condicion>

true <cuerpo bucle>

<condicion>

true

false

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

145

II.2.1.2.

Algunos usos de los bucles

Ejemplo. Crear un ltro (lter) de entrada de datos: Leer un valor y no permitir al usuario que lo introduzca fuera de un rango determinado.

// Introducir un nico valor, pero positivo. // Imprimir el coseno. #include <iostream> #include <cmath> using namespace std; int main(){ double valor; do{ cout << "\nIntroduzca un valor positivo: "; cin >> valor; }while (valor < 0); cout << cos(valor); }
Nota. El ltro anterior no nos evita todos los posibles errores. Por ejemplo, si se introduce un valor demasiado grande, se produce un desbordamiento y el resultado almacenado en valor es indeterminado. Nota. Observad que el estilo de codicacin se rige por las mismas normas que las indicadas en la estructura condicional (pgina 97)

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

146

Ejemplo. Escribir 20 lneas con 5 estrellas cada una.

num_lineas = 1; do{ cout << '\n' << "*****" ; num_lineas = num_lineas + 1; }while (num_lineas <= 20);
O bien:

// nuevo = antiguo + 1

num_lineas = 0; do{ cout << '\n' << "*****" ; num_lineas = num_lineas + 1; }while (num_lineas < 20);

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

147

O bien:

num_lineas = 1; while (num_lineas <= 20){ cout << '\n' << "*****" ; num_lineas = num_lineas + 1; }
Preferible:

num_lineas = 0;

// Llevo 0 lneas impresas

while (num_lineas < 20){ cout << '\n' << "*****" ; num_lineas = num_lineas + 1; }
Dentro del bucle, JUSTO antes de comprobar la condicin, la variable total contiene el nmero de lneas que hay impresas :-) Nota. Podramos usar el operador de incremento:

while (num_lineas < 20){ cout << '\n' << "*****" ; num_lineas++; }

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

148

Eleccin entre un bucle pre-test o post-test: Hay situaciones en las que no queremos que se ejecute el cuerpo del bucle? S pre-test, No post-test Ejercicio. Leer un nmero positivo tope e imprimir tope lneas con 5 estrellas cada una.

cout << "\nCuntas lneas de asteriscos quiere imprimir? "; cin >> tope; num_lineas = 0; do{ cout << '\n' << "*****" ; num_lineas++; }while (num_lineas < tope);
Problema: Qu ocurre si tope = 0? Ejercicio. Resolved el problema anterior con un bucle pre-test

'

Consejo:

&

Fomentad el uso de los bucles pre-test. Casi siempre habr algn caso en el que no queramos ejecutar el cuerpo del bucle ni siquiera una vez.

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

149

Ejemplo. Leed un entero tope y escribir los pares tope

cin >> tope; par = 0; while (par <= tope){ par = par + 2; cout << par; }
Al nal, escribe uno ms. Cambiamos el orden de las instrucciones:

cin >> tope; par = 0; while (par <= tope){ cout << par; par = par + 2; }

// Primer candidato // Es bueno? // Si => imprmelo // calcular nuevo // candidato // No => Salir

Si no queremos que salga 0, cambiaramos la inicializacin:

par = 2
' $

Consejo:

&

En el diseo de los bucles siempre hay que comprobar el correcto funcionamiento en los casos extremos (primera y ltima iteracin)

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

150

Ejemplo. Calculad el nmero de dgitos que tiene un entero

57102 -> 5 dgitos 45 -> 2 dgitos


Algoritmo: Entradas: n Salidas: num_digitos Descripcin e implementacin:

Ir dividiendo n por 10 hasta llegar a una cifra El nmero de dgitos ser el nmero de iteraciones num_digitos = 1; while (n > 9){ n = n/10; num_digitos++; }
Mejor si no modicamos la variable original:

n_dividido = n; num_digitos = 1; while (n_dividido > 9){ n_dividido = n_dividido/10; num_digitos++; }

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

151

II.2.1.3.

Lectura Anticipada

Ejemplo. Realizad un programa que sume una serie de valores ledos desde teclado, hasta que se lea el valor -1 (terminador = -1)

#include<iostream> using namespace std; int main(){ int suma, numero; suma = 0; do{ cin >> numero; suma = suma + numero; }while (numero != -1); cout << "\nLa suma es " << suma; }
Problema: Procesa el -1 y lo suma.

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

152

Una primera solucin:

do{ cin >> numero; if (numero != -1) suma = suma + numero; }while (numero != -1);
Funciona, pero evala dos veces la misma condicin, lo cual es ineciente y, mucho peor, duplica cdigo. Recordad: Evitad el uso de bucles do while Solucin: tcnica de lectura anticipada. Leemos el primer valor antes de entrar al bucle y comprobamos si hay que procesarlo (el primer valor podra ser ya el terminador)

suma = 0; cin >> numero;

// Primer candidato

while (numero != -1) { // Es bueno? suma = suma + numero; // Lo procesamos cin >> numero; // Leer siguiente candidato } cout << "\nLa suma es " << suma; }
Nota. La primera vez que entra al bucle, la instruccin

while (numero != -1)


hace las veces de un condicional. De esta forma, controlamos si hay que procesar o no el primer valor.

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

153

Ejercicio.

// Programa que va leyendo nmeros enteros hasta que se // lea el cero. Imprimir el nmero de pares e impares ledos. #include <iostream> using namespace std; int main(){ int ContPar, ContImpar, valor; ContPar=0; ContImpar=0; cout << "\nIntroduce valor: "; cin >> valor; while ( if ( else ; cout << "\nIntroduce valor: "; cin >> valor; } cout << "\nFueron " << ContPar << " pares y " << ContImpar << " impares"; } ) { ) ;

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

154

II.2.1.4.

Condiciones compuestas

Es normal que necesitemos comprobar ms de una condicin en un bucle. Dependiendo del algoritmo necesitaremos conectarlas con && o con ||. Ejemplo. Leer una opcin de un men. Slo se admite s n.

char opcion; do{ cout << "Desea formatear el disco?"; cin >> opcion; }while ( opcion!='s' opcion!='S' opcion!='n' opcion!='N' );
Cundo quiero salir del bucle? Cuando cualquiera de las condiciones sea false. Cual es el operador que cumple lo siguiente?:

false

Operador

<lo que sea>

= false

Nota. En este ejemplo, mucho mejor si pasamos la opcin a mayscula dentro del bucle y comprobamos nicamente las condiciones con los caracteres en mayscula

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

155

Ejemplo. Leer dos valores desde el teclado forzando a que ambos sean distintos de cero.

do{ cout << "\nIntroduzca un numero: "; cin >> dato1; cout << "\nIntroduzca otro numero: "; cin >> dato2; }while (dato1==0 dato2==0);

Cundo quiero salir del bucle? Cuando ambas condiciones, simultneamente , sean false. En cualquier otro caso, entro de nuevo al bucle. Cual es el operador que cumple lo siguiente?:

false true

Operador Operador

false = false <lo que sea> =

true

En cualquier caso, hubiese sido mucho mejor leer cada valor en un bucle independiente. De esa forma, si nos equivocamos al introducir uno pero no el otro, slo tendremos que volver a leer el valor incorrecto. Hacedlo en la casa.
' $

Consejo:

&

E n la construccin de condiciones compuestas, empezad planteando las condiciones simples que la forman. Pensad cuando queremos salir del bucle y conectad adecuadamente dichas condiciones simples, dependiendo de si nos queremos salir cuando todas simultneamente sean false (OR) o cuando cualquiera de ellas sea false (AND)

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

156

Ejemplo. Calcular el mximo comn divisor de dos nmeros a y b. Algoritmo: Entradas: Los dos enteros a y b Salidas: el entero max_com_div, mximo comn divisor de a y b Descripcin e Implementacin:

/* Empezar como primer posible divisor con el menor de ambos nmeros Mientras divisor no divida a ambos, probar con el divisor anterior */ if (b<a) menor = b; else menor = a; divisor = menor; while ((a % divisor != 0) divisor --; max_com_div = divisor; (b % divisor != 0))

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

157

El uso de una variable lgica har que el algoritmo sea ms fcil de entender:

mcd_encontrado = false; while (!mcd_encontrado){ if ((a%divisor == 0) (b%divisor == 0)) mcd_encontrado = true; else divisor--; } max_com_div = divisor;
Qu pasara si quitsemos el else?

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

158

Ejemplo. Encontrar el primer divisor propio impar de un nmero.

Recorrer los impares menores que el nmero hasta encontrar un divisor o hasta llegar a dicho nmero int impar; cin >> n; impar = 3; while (n % impar != 0 && impar = impar + 2; n > impar)

Una vez terminado el bucle, cmo comprobamos cual fue la condicin que nos hizo salir?

if (n % impar == 0) cout << "\nPrimer divisor impar: " << impar; else cout << "\n" << n << " no tiene divisores impares propios";
Y si el bucle termin por la otra condicin (n es un primo igual a impar)? En este caso n % impar sera tambin cero, pero no queremos imprimir el mismo n como un divisor suyo.

impar = 3; while (n % impar != 0 && impar = impar+2; n > impar)

if (impar < n && n % impar == 0) cout << "\nPrimer divisor impar: " << impar; else cout << "\n" << n << " no tiene divisores impares propios";

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

159

Repetimos la evaluacin de condiciones equivalentes. Solucin: Usamos variables lgicas:

bool hay_posibles_divisores, divisor_encontrado; hay_posibles_divisores = true; divisor_encontrado = false; impar = 3; while (!divisor_encontrado && hay_posibles_divisores){ if (impar >= n) hay_posibles_divisores = false; else if (n % impar == 0) // Importante el orden divisor_encontrado = true; // al evaluar las condiciones else impar = impar+2; } if (divisor_encontrado) cout << "\nPrimer divisor impar: " << impar; else cout << "\n" << n << " no tiene divisores impares propios";
Nota. Podramos salir del bucle en n/2
' $

Consejo:

&

Fomentad el uso de variables lgicas para controlar condiciones complejas de salida de los bucles. Usaremos tantas variables lgicas como condiciones necesitemos controlar, y las conectaremos apropiadamente con los operadores lgicos.

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

160

Ejemplo. Leer nmeros enteros de la entrada por defecto hasta que se introduzcan 10 hasta que se introduzca un nmero negativo. Imprimir la media aritmtica.

suma = 0; cin >> valor; total_introducidos = 1; while ((valor >= 0) && (total_introducidos <= 10)){ suma = suma + valor; total_introducidos++; cin >> valor; } media = suma/total_introducidos;
Problema: Lee el undcimo y se sale, pero ha tenido que leer dicho valor. Solucin: O bien cambiamos la inicializacin de total_introducidos a 0, o bien leemos hasta 9. En cualquier caso, el dcimo valor hay que procesarlo fuera del bucle.

....... while ((valor >= 0) && (total_introducidos < 10)){ suma = suma + valor; total_introducidos++; cin >> valor; } suma = suma + valor; media = suma/total_introducidos;

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

161

Problema: Si se ha salido con un negativo lo suma. Adems, total_introducidos tambin se incrementa en uno con el valor negativo, por lo que habra que tenerlo en cuenta a la hora de hallar la media aritmtica. Quedara:

suma = 0; cin >> valor; total_introducidos = 1; while ((valor >= 0) && (total_introducidos<10)){ suma = suma + valor; total_introducidos++; cin >> valor; } if (total_introducidos == 10) suma = suma + valor; else total_introducidos--; media = suma/total_introducidos;
Pero y si el ltimo ledo es negativo?

if ((total_introducidos == 10) && (valor >=0)) suma = suma + valor; else total_introducidos--;
Podemos observar la complejidad (por no decir chapucera) innecesaria que ha alcanzado el programa.

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

162

Replanteamos desde el inicio la solucin y usamos mejor variables lgicas:

suma = 0; num_positivos = 0; es_positivo = true; llevo_menos_de_10 = true; while (es_positivo && llevo_menos_de_10){ cin >> valor; if (valor < 0) es_positivo = false; else{ suma = suma + valor; num_positivos++; if (num_positivos == 10) llevo_menos_de_10 = false; } } media = suma/(1.0*num_positivos); // Si num_positivos es 0 // media = infinito (correcto) if (num_positivos == 0) cout << "\nNo se introdujeron valores"; else cout << "\nMedia aritmtica = " << media;
 

Consejo:


Construid los bucles de forma que no haya que arreglar nada despus de su nalizacin

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

163

Bajemos puntos en el examen. El algoritmo es el mismo, pero observad los nombres de variables:

aux = 0; contador = 0; seguir_1 = true; seguir_2 = true; while (seguir_1 && seguir_2){ cin >> v; if (v < 0) seguir_1 = false; else{ aux = aux + v; contador++; if (contador == 10) seguir_2 = false; } } resultado = aux/(1.0*contador); if (contador == 0) cout << "\nNo se introdujeron valores"; else cout << "\nMedia aritmtica = " << resultado;

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

164

Algunas citas sobre la importancia de escribir cdigo que sea fcil de entender:
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand". Martin Fowler "Programs must be written for people to read, and only incidentally for machines to execute". Abelson & Sussman "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live".

Un principio de programacin transversal:

Principio de Programacin: Sencillez (Simplicity) Fomentad siempre la sencillez y la legibilidad en la escritura de cdigo

"There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deciencies, and the other way is to make it so complicated that there are no obvious deciencies. The rst method is far more difcult.". C.A.R. Hoare

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

165

Ejemplo. Comprobar si un nmero es primo.

#include <iostream> #include <cmath> using namespace std; int main(){ int valor, divisor; bool es_primo; cout << "Introduzca un numero natural: "; cin >> valor; es_primo = true; divisor = 2 while (divisor < valor){ if (valor % divisor == 0) es_primo = false; divisor++; } if (es_primo) cout << valor << " es primo\n"; else cout << valor << " no es primo\n"; }
Para hacerlo ms eciente, nos salimos en cuanto sepamos que no es primo. Nos salimos del bucle con un bool. La misma variable es_primo nos sirve:

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

166

es_primo = true; divisor = 2 while (divisor < valor && es_primo){ if (valor % divisor == 0) es_primo = false; else divisor++; }
Incluso podramos quedarnos en sqrt(valor), ya que si valor no es primo, tiene al menos un divisor menor que sqrt(valor). En cualquier caso, sqrt es una operacin costosa y habra que evaluarlo empricamente.

es_primo = true; tope = sqrt(valor); divisor = 2 while (divisor < tope && es_primo){ if (valor % divisor == 0) es_primo = false; else divisor++; }
Nota. Realmente, para que compile sin problemas debemos poner tope = sqrt(1.0*valor);

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

167

Ampliacin:
Cuando valor es un entero muy grande, el algoritmo anterior no termina en un tiempo razonable. Qu es un nmero grande?

http://www.naturalnumbers.org/bignum.html
Qu signica tiempo razonable? Est fuera del alcance del curso e implica nociones ms profundas sobre complejidad computacional Para una introduccin informal pero clara:

http://www.claymath.org/Popular_Lectures/Minesweeper/
El problema terico ms importante en Informtica es determinar si existen problemas que no pueden resolverse en un tiempo razonable con un algoritmo (aunque s exista un algoritmo que compruebe rpidamente si una propuesta es una solucin o no). Este problema est an sin resolver y es uno de los siete problemas del milenio, recompensado con 1 milln de dlares por el Instituto Clay de Matemticas. En Agosto de 2010 un cientco de HP proclam haberlo demostrado, pero en pocas semanas se encontraron fallos en la demostracin. El primer algoritmo para determinar en un tiempo razonable si un nmero es primo, es bastante reciente (2002):

Wikipedia -> AKS primality test


Sobre nmeros primos en general:

http://primes.utm.edu/

Estructuras de Control Estructuras repetitivas Bucles controlados por condicin: pre-test y post-test

168

II.2.1.5.

Bucles sin n

aquim Ejercicio. Cuantas iteraciones se producen?

contador = 2; while (contador < 3) { contador--; cout << '\n' << contador; }

contador = 1; while (contador != 10) { contador = contador + 2; }

Fomentad el uso de condiciones de desigualdad.

contador = 1; while (contador <= 10) { contador = contador + 2; }

Estructuras de Control Estructuras repetitivas Bucles controlador por contador

169

II.2.2.
II.2.2.1.

Bucles controlador por contador


Motivacin

Se utilizan para repetir un conjunto de sentencias un nmero de veces jado de antemano. Se necesita una variable contadora, un valor inicial, un valor nal y un incremento. Ejemplo. Hallar la media aritmtica de cinco enteros ledos desde teclado.

int main(){ int contador, valor, suma, inicio, final; double media; inicio = 1; final = 5; suma = 0; contador = inicio; while (contador <= final){ cout << "\nIntroduce un nmero "; cin >> valor; suma = suma + valor; contador = contador + 1; } media = suma / (final *1.0); cout << "\nLa media es " << media; }

Estructuras de Control Estructuras repetitivas Bucles controlador por contador

170

contador = inicio

false

contador <= final

true

cuerpo del bucle

contador = contador + 1

contador es la variable controladora del ciclo. inicio es el valor inicial que toma la variable controladora. final es el valor nal que toma la variable controladora.

Estructuras de Control Estructuras repetitivas Bucles controlador por contador

171

II.2.2.2.

Formato

La sentencia for permite la construccin de una forma compacta de los ciclos controlados por contador, aumentando la legibilidad del cdigo.

int main(){ int contador, valor, suma, inicio, final; double media; inicio = 1; final = 5; suma = 0; for (contador = inicio ; contador <= final ; contador = contador + 1){ cout << "\nIntroduce un nmero "; cin >> valor; suma = suma + valor; } media = suma / (final*1.0); cout << "\nLa media es " << media; }

Estructuras de Control Estructuras repetitivas Bucles controlador por contador

172

for (contador = inicio ; contador <= final ; contador = contador + 1){ cout << "\nIntroduce un nmero "; cin >> valor; suma = suma + valor; } contador = inicio es la asignacin inicial de la variable contadora.
Si usamos como condicin

contador < final


se producir una iteracin menos.

contador = contador + 1 aumenta en 1 el valor de contador en cada iteracin. Por abreviar, suele usarse contador++ en vez de contador = contador + 1 for (contador = inicio ; contador <= final ; contador++)
Podemos usar cualquier otro incremento:

contador--; contador = contador - 4;


En el caso de incrementos negativos, la condicin de terminacin del bucle tendr que ser del tipo: contador >= final

Estructuras de Control Estructuras repetitivas Bucles controlador por contador

173

for ([<contador = valor inicial>] ; [<condicin sobre contador>];


[<actualizacin del contador>]) <cuerpo del bucle>

contador = valor inicial

false

condicin sobre contador

true

cuerpo del bucle

actualizacin del contador

Estructuras de Control Estructuras repetitivas Bucles controlador por contador

174

Encuentre errores en este cdigo:

For {x = 100, x>=1, x++} cout << x << " ";

Ejemplo. Cuntos pares hay en [10, 10]?

int candidato, num_pares; num_pares = 0; for(candidato = -10; candidato <= 10; candidato++) { if (candidato % 2 == 0) num_pares++; } cout << "\nHay " << num_pares << " pares";
Este problema tambin se podra haber resuelto como sigue:

int num_pares, par; num_pares = 0; for (par = -10; par <= 10; par = par+2) num_pares++; cout << "\nHay " << num_pares << " pares";

Estructuras de Control Estructuras repetitivas Bucles controlador por contador

175

Ejemplo. Imprimir 9 veces el mensaje Hola

int i; for (i = 1; i <= 9; i++) cout << "\nHola";


Con qu valor sale la variable i? 10 Cuando termina un bucle for, la variable contadora se queda con el primer valor que hace que la condicin del bucle sea falsa. Cuntas iteraciones se producen en un for? Si incremento = 1, inicio es menor que final y la condicin es contador <= final final - inicio + 1 Si incremento = 1, inicio es menor que final y la condicin es contador < final final - inicio

for (i = 0; i < 9; i++) cout << "\nHola"; for (i = 9; i > 2; i--) cout << "\nHola"; for (i = 9; i >= 2; i--) cout << "\nHola";

-->

9 - 0 = 9

-->

9 - 2 = 7

-->

9 - 2 + 1 = 8

Estructuras de Control Estructuras repetitivas Bucles controlador por contador

176

Nmero de iteraciones con incrementos cualesquiera. Si es del tipo contador <= final, tenemos que contar cuntos intervalos de longitud igual a incremento hay entre los valores inicio y final. El nmero de iteraciones ser uno ms. En el caso de que contador < final, habr que contar el nmero de intervalos entre inicio y final - 1. El nmero de intervalos se calcula a travs de la divisin entera. En resumen (considerando incrementos positivos): Si el bucle es del tipo contador <= final el nmero de iteraciones es (final - inicio) / incremento + 1 siempre y cuando sea inicio <= final. En otro caso, hay 0 iteraciones. Si el bucle es del tipo contador < final el nmero de iteraciones es (final - 1 - inicio) / incremento + 1 siempre y cuando sea inicio < final. En otro caso, hay 0 iteraciones. De forma anloga se realizan los clculos con incrementos negativos.
#

"

Usaremos los bucles for cuando sepamos, antes de entrar al bucle, el nmero de iteraciones que se tienen que ejecutar.

Estructuras de Control Estructuras repetitivas Bucles controlador por contador

177

Ejercicio. Qu salida producen los siguientes trozos de cdigo?

int i, suma_total; suma_total = 0; for (i = 1 ; i <= 10; i++) suma_total = suma_total + 3; cout << suma_total;

suma_total = 0; for (i = 5 ; i <= 36 ; i = i+4) suma_total++;

suma_total = 0; i = 5; while (i <= 36){ suma_total++; i = i + 4; }

Estructuras de Control Estructuras repetitivas Anidamiento de bucles

178

II.2.3.

Anidamiento de bucles

Dos bucles se encuentran anidados, cuando uno de ellos est en el bloque de sentencias del otro. En principio no existe lmite de anidamiento, y la nica restriccin que se debe satisfacer es que deben estar completamente inscritos unos dentro de otros.

ANIDAMIENTO PERMITIDO

ANIDAMIENTO NO PERMITIDO

Estructuras de Control Estructuras repetitivas Anidamiento de bucles

179

Ejemplo. Imprimir la tabla de multiplicar de los TOPE primeros nmeros.

#include <iostream> using namespace std; int main(){ const int TOPE = 3; int i, j; for (i = 1 ; i <= TOPE ; i++) { for (j = 1 ; j <= TOPE ; j++) cout << i << "*" << j << "=" << i*j << " cout << "\n"; } }

";

j=1 Salida: i=1 1*1 = 1 i=2 2*1 = 2 i=3 3*1 = 3

j=2

j=3

1*2 = 2 2*2 = 4 3*2 = 6

1*3 = 3 2*3 = 6 3*3 = 9

Estructuras de Control Estructuras repetitivas Anidamiento de bucles

180

Ejemplo. Qu salida producen el siguiente cdigo?

iteraciones = 0; suma = 0; for (i = 1 ; i <= n; i++){ for (j = 1 ; j <= n; j++){ suma = suma + j; iteraciones++; } }
Nmero de iteraciones: n2 Valor de la variable suma. Supongamos n= 5

1 1 1 1 1

+ + + + +

2 2 2 2 2

+ + + + +

3 3 3 3 3

+ + + + +

4 4 4 4 4

+ + + + +

5 5 5 5 5

suma = 5 * (1 + 2 + 3 + 4 + 5). En general:


i=n

suma = n
i=1

i=n

n2 + n 2

n3 + n2 2

Si n es 5, suma se quedar con 75

Estructuras de Control Estructuras repetitivas Anidamiento de bucles

181

Ejemplo. Qu salida producen el siguiente cdigo?

iteraciones = 0; suma = 0; for (i = 1 ; i <= n; i++){ for (j = i ; j <= n; j++){ iteraciones++; suma = suma + j; } }
Nmero de iteraciones:
i=n

n + (n 1) + (n 2)+ +1 =
i=1

i=

n2 + n 2

< n2

Valor de la variable suma. Supongamos n= 5

1 + 2 + 3 + 4 + 2 + 3 + 4 + 3 + 4 + 4 +

5 5 5 5 5
i=n

suma = 5 5 + 4 4 + 3 3 + 2 2 + 1 1 =
i=1

i2 =

1 6

n(n + 1)(2n + 1)

Si n es 5, suma se quedar con 55

Estructuras de Control Estructuras repetitivas Anidamiento de bucles

182

Ejemplo. Imprimir en pantalla los divisores primos del entero n Algoritmo: Entradas: n Salidas: ninguna Descripcin: Recorrer todos los enteros menores que n Comprobar si el entero es primo. En dicho caso, comprobar si divide a n Ineciente. Es mejor el siguiente: Recorrer todos los enteros menores que n Comprobar si el entero divide a n. En dicho caso, comprobar si el entero es primo. Nota. Mejor an si empezamos desde n/2

Estructuras de Control Estructuras repetitivas Anidamiento de bucles

183

n divisor_n

18 9

8 7

5 4

3 2

for (divisor_n = n/2 ; divisor_n > 1 ; divisor_n--){ if (n % divisor_n == 0){ es_primo = true; tope = sqrt(1.0*divisor_n); divisor_primo = 2; while (divisor_primo <= tope && es_primo){ if (divisor_n % divisor_primo == 0) es_primo = false; else divisor_primo++; } if (es_primo) cout << "\nEl primo " << divisor_n << " divide a " << n; } }

Estructuras de Control Estructuras repetitivas Anidamiento de bucles

184

Ejemplo. El Teorema fundamental de la Aritmtica (Euclides 300 A.C/Gauss 1800) nos dice que podemos expresar cualquier entero como producto de factores primos. Imprimir en pantalla dicha descomposicin.

n 360 180 90 45 15 5 1

primo 2 2 2 3 3 5

Fijamos un valor de primo cualquiera. Por ejemplo primo=2

// Dividir n por primo cuantas veces sea posible primo = 2; while (n % primo == 0){ cout << primo << " "; n = n / primo; }
Ahora debemos pasar al siguiente primo primo y volver a ejecutar el bloque anterior. Condicin de parada: n>=primo o bien n>1

Mientras n > 1 Dividir n por primo cuantas veces sea posible primo = siguiente primo mayor que primo
Cmo pasamos al siguiente primo?

Estructuras de Control Estructuras repetitivas Anidamiento de bucles

185

primo++; Recorrer todos los enteros menores de primo hasta encontrar un divisor o hasta llegar a primo
Este recorrido implica un bucle, pero no es necesario. Hagamos simplemente primo++:

/* Mientras n > 1 Dividir n por primo cuantas veces sea posible primo++ */ primo = 2; while (n > 1){ while (n % primo == 0){ cout << primo << " "; n = n / primo; } primo++; }
Corremos el peligro de intentar dividir n por un valor primo que no sea primo? No. Por ejemplo, n=40. Cuando primo sea 4, podr ser n divisible por 4, es decir n%4==0? Despus de dividir todas las veces posibles por 2, me queda n=5 que ya no es divisible por 2, ni por tanto, por ningn mltiplo de 2. En general, al evaluar n%primo, n ya ha sido dividido por todos los mltiplos de primo. Nota. Podemos sustituir p++ por primo=primo+2 (tratando el primer caso primo=2 de forma aislada)

Estructuras de Control Estructuras repetitivas Anidamiento de bucles

186

Ampliacin:
No hay forma de calcular el siguiente primo a uno dado (con una frmula directa). Como mucho, se puede establecer una cota del nmero de primos que hay menores a uno dado. Este problema est ligado (demostrado por Von Koch en 1901) a la Hiptesis de Riemann, uno de los problemas matemticos ms importantes sin resolver, y por el cual se ofrece una recompensa de 1 milln de dlares (por el Instituto Clay de Matemticas) Riemann fue un gran matemtico, discpulo de Gauss. Entre otras cosas, desarroll la geometra de Riemann, base fundamental de la teora de la relatividad de Einstein.

Ampliacin:
El problema de factorizar un nmero (expresarlo como producto de factores primos) es muy importante en la vida real. Hasta la fecha, no se ha conseguido construir (ni se espera que se consiga) un algoritmo que termine en un tiempo razonable para factorizar un nmero cuando ste es grande. Los conceptos de nmero grande y tiempo razonable se presentaron en la pgina 167. Dnde se aplica? En Criptografa (Cryptography) , para ocultar nuestros datos en Internet (por ejemplo, el nmero de la tarjeta de crdito). Mientras no se disee un algoritmo en este sentido, nuestros datos bancarios estn bien protegidos de los sniffers . Consultad:

http://angelrey.wordpress.com/2009/05/27/ numeros-primos-criptologia-y-codificacion/
Buscad en Internet: Criptografa asimtrica, Integer factorization, RSA numbers

Estructuras de Control Estructuras repetitivas Particularidades de C++

187

II.2.4.

Particularidades de C++

C++ es un lenguaje muy verstil. A veces, demasiado II.2.4.1. Expresiones y sentencias son similares

El tipo bool como un tipo entero En C++, el tipo lgico es compatible con un tipo entero. Cualquier expresin entera que devuelva el cero, se interpretar como false. Si devuelve cualquier valor distinto de cero, se interpretar como true.

bool var_logica; var_logica = false; var_logica = (4>5); var_logica = 0; var_logica = (4<5); var_logica = true; var_logica = 2;

// Correcto: resultado false // Correcto: resultado 0 (false) :-O // Correcto: resultado true // Correcto: resultado 2 (true) :-O

Nota. Algunos compiladores, al ejecutar cout << false, imprimen en pantalla un cero, mientras que cout << true imprime un uno. La dualidad entre los tipos enteros y lgicos nos puede dar quebraderos de cabeza en los condicionales

Estructuras de Control Estructuras repetitivas Particularidades de C++

188

int dato = 4; if (! dato < 5) cout << dato <<" es mayor o igual que 5"; else cout << dato <<" es menor de 5";
El operador ! tiene ms precedencia que <. Por lo tanto, la evaluacin es como sigue: ! dato < 5 (!dato) < 5 (dato vale 4) (!true) < 5 false < 5 0 < 5 true Imprime 4 es mayor o igual que 5! Solucin:

if (! (dato < 5)) cout << dato <<" es mayor o igual que 5"; else cout << dato <<" es menor de 5";
o mejor:

if (dato >= 5) cout << dato <<" es mayor o igual que 5"; else cout << dato <<" es menor de 5";
 

Consejo:


No hay que ser rcano con los parntesis




Estructuras de Control Estructuras repetitivas Particularidades de C++

189

El operador de asignacin en expresiones El operador de asignacin = se usa en sentencias del tipo:

valor = 7;
Pero adems, devuelve un valor: el resultado de la asignacin. As pues, valor = 7 es una expresin que devuelve 7

un_valor = otro_valor = valor = 7;


Esto producir fuertes dolores de cabeza cuando por error usemos una expresin de asignacin en un condicional:

valor = 5; if (valor = 7) <acciones if> // Siempre se ejecuta este bloque! else <acciones else> // Adems, valor se queda con 7 valor = 7 devuelve 7. Al ser distinto de cero, es true. Por tanto, se ejecuta el bloque if (y adems valor se ha modicado con 7) a = 7; if (a=0) cout << "\nRaz= " << -c/b; // Nunca se ejecuta else{ r1 = -b + sqrt(b*b -4*a*c) / (2*a) ; // Error lgico

Estructuras de Control Estructuras repetitivas Particularidades de C++

190

El operador de igualdad en sentencias

C++ permite que una expresin constituya una sentencia Esta particularidad no da benecios salvo en casos muy especcos y sin embargo nos puede dar quebraderos de cabeza. As pues, el siguiente cdigo compila perfectamente:

int entero; 4 + 3;
C++ evala la expresin entera 4 + 3;, devuelve 7 y no hace nada con l, prosiguiendo la ejecucin del programa.

int entero; entero == 7;


C++ evala la expresin lgica entero == 7;, devuelve true y no hace nada con l, prosiguiendo la ejecucin del programa.

Estructuras de Control Estructuras repetitivas Particularidades de C++

191

El operador de incremento en expresiones

variable = 9; if (variable + 1 == 10) cout << variable << " es igual a 9"; cout << variable; // Imprime 9 // Correcto

El operador ++ (y --) forma una expresin: devuelve el valor incrementado:

variable = 9; if (variable++ == 10) cout << variable << " es igual a 9"; // "10 es igual a 9" cout << variable;


// "10"


Consejo:


No usad = ni ++ en la expresin lgica de una sentencia condicional

Estructuras de Control Estructuras repetitivas Particularidades de C++

192

II.2.4.2.

El bucle for en C++

Bucles for con cuerpo vaco El siguiente cdigo no imprime los enteros del 1 al 20. Por qu?

for (x = 1; x <= 20; x++); cout << x;


Realmente, el cdigo bien tabulado es:

for (x = 1; x <= 20; x++) ; cout << x;


Bucles for con sentencias de incremento incorrectas Lo siguiente es un error lgico:

for (par = -10; par <= 10; par + 2) num_pares++;


equivale a:

// en vez de par = par + 2

par = -10; while (par <= 10){ num_pares++; par + 2; }


Compila correctamente pero la sentencia par + 2; no incrementa par (recordad lo visto en la pgina 190) Resultado: bucle innito.

Estructuras de Control Estructuras repetitivas Particularidades de C++

193

Modicacin del contador nicamente mirando la cabecera de un bucle for sabemos cuantas iteraciones se van a producir (recordar lo visto en la pgina 176). Por eso, en los casos en los que sepamos de antemano cuntas iteraciones necesitamos, usaremos un bucle for. En otro caso, usaremos un bucle while do while. Para mantener dicha nalidad, es necesario respetar la siguiente restriccin: No se debe modicar el valor de la variable controladora, ni el valor nal dentro del cuerpo del bucle for

Sin embargo, C++ no impone dicha restriccin. Ser responsabilidad del programador. Ejemplo. Sumar los divisores de valor. Dnde est el fallo en el siguiente cdigo?:

suma = 0; tope = valor/2; for (divisor = 2; divisor <= tope ; divisor++) { if (valor % divisor == 0) suma = suma + divisor; divisor++; }

Estructuras de Control Estructuras repetitivas Particularidades de C++

194

Supongamos que quiero salir de un bucle for cuando se produce una condicin. Cmo lo hago? Ejemplo. Escribe los enteros entre inf y sup, hasta llegar al primer mltiplo de 13:

cin >> inf; cin >> sup; for (entero = inf; entero <= sup; entero++) { cout << entero << " "; if (entero % 13 == 0) entero = sup + 1; }
Esto funciona pero es una chapuza. Mejor usamos un while:

// :-(

cin >> inf; cin >> sup; entero = inf; while (entero <= sup) && (entero % 13 != 0){ cout << entero << " "; }

Estructuras de Control Estructuras repetitivas Particularidades de C++

195

Ejemplo. Comprobar si un nmero es primo

es_primo = true; for (divisor = 2 ; divisor < valor ; divisor++) if (valor % divisor == 0){ es_primo = false; divisor = valor; // :-( }
Mejor la solucin que vimos en la pgina 166:

es_primo = true; divisor = 2 while (divisor < valor && es_primo){ if (valor % divisor == 0) es_primo = false; else divisor++; }

Estructuras de Control Estructuras repetitivas Particularidades de C++

196

El bucle for como ciclo controlado por condicin Si bien en muchos lenguajes tales como PASCAL, FORTRAN o BASIC el comportamiento del ciclo for es un bucle controlado por contador, en C++ es un ciclo ms verstil, controlado por condicin. En el caso concreto de C++, su sintaxis es la siguiente:

for ([<sentencia inicial>];


[<expresin lgica>]; [<sentencia nal>]) <cuerpo bucle>

donde, <sentencia inicial> es la sentencia que se ejecuta antes de entrar al bucle, <expresin lgica> es cualquier condicin que verica si el ciclo debe terminar o no, <sentencia nal> es la sentencia que se ejecuta antes de volver arriba para comprobar el valor de la expresin lgica. Por tanto, la condicin impuesta en el ciclo no tiene por qu ser de la forma contador < final, sino que puede ser cualquier tipo de condicin.

Estructuras de Control Estructuras repetitivas Particularidades de C++

197

sentencia inicial

false

expresin lgica

true

cuerpo del bucle

sentencia final

Estructuras de Control Estructuras repetitivas Particularidades de C++

198

Ejemplo. Comprobar si un nmero es primo. Lo resolvimos en la pgina 166:

es_primo = true; divisor = 2 while (divisor < valor && es_primo){ if (valor % divisor == 0) es_primo = false; else divisor++; }
Con un for quedara:

es_primo = true; divisor = 2 for (divisor = 2; divisor < valor && es_primo; divisor++) if (valor % divisor == 0) es_primo = false;

Estructuras de Control Estructuras repetitivas Particularidades de C++

199

Ejemplo. Escribe los enteros entre inf y sup, hasta llegar al primer mltiplo de 13 (lo vimos en la pgina 194)

cin >> inf; cin >> sup; entero = inf; while (entero <= sup && entero % 13 != 0){ cout << entero << " "; entero++; }

cin >> inf; cin >> sup; for (entero = inf; entero <= sup && entero % 13 != 0 ; entero++) cout << entero << " ";
En los ejemplos anteriores

for (entero = inf; entero<=sup && entero%13 != 0 ; entero++) for (divisor = 2; divisor <= tope && es_primo; divisor++)
se ha usado dentro del for dos condiciones que controlan el bucle: La condicin relativa a la variable contadora. Otra condicin adicional. Este cdigo es completamente aceptable en C++.

Estructuras de Control Estructuras repetitivas Particularidades de C++ '

200 $

En resumen, usaremos un bucle for en los casos en los que siempre exista: Una sentencia de inicializacin del contador Una condicin de continuacin que involucre al contador (pueden haber otras condiciones adicionales)
&

Una sentencia nal que involucre al contador

Estructuras de Control Estructuras repetitivas Particularidades de C++

201

Pero ya puestos, puede usarse entonces, cualquier condicin dentro de la cabecera del for? S, pero no es muy recomendable. Ejemplo. Construir un programa que indique el nmero de valores que introduce un usuario hasta que se encuentre con un cero.

// Programa para contar el numero de valores que se // introducen hasta que se encuentra un cero. // --- Usando un ciclo while --#include <iostream> using namespace std; int main(){ int num_valores, valor; cin >> valor; num_valores = 0; while (valor != 0){ cin >> valor; num_valores++; } cout << "El nmero de valores introducidos es " << num_valores; }

Estructuras de Control Estructuras repetitivas Particularidades de C++

202

Lo hacemos ahora con un for:

// Programa para contar el nmero de valores que se // introducen hasta que se encuentra un cero. // --- Usando un ciclo for --#include <iostream> using namespace std; int main(){ int num_valores, valor; cin >> valor; for (num_valores=0; valor!=0; num_valores++) cin >> valor; cout << "\nEl nmero de valores introducidos es " << num_valores; }
Debemos evitar este tipo de bucles for en los que la(s) variable(s) que aparece en la condicin, no aparece en las otras dos expresiones.

Estructuras de Control Estructuras repetitivas Particularidades de C++

203

En el anterior ejemplo, si cambiamos los nombres de las variables, tendramos:

for (recorr=0; recoger!=0; recorr++) .....


Y el cerebro de muchos programadores le engaar y le harn creer que est viendo lo siguiente, que es a lo que est acostumbrado:

for (recorr=0; recorr!=0; recorr++) .....


Esto no quiere decir que, ADEMS de la variable contadora, no podamos usar condiciones adicionales para salirnos del bucle. Ser algo usual (lo hicimos en el ejemplo del primo)

Y ya puestos, podemos suprimir algunas expresiones de la cabecera de un bucle for? La respuesta es que s, pero hay que evitarlas SIEMPRE. Oscurecen el cdigo. Ejemplo. Sumar valores ledos desde la entrada por defecto, hasta introducir un cero.

int main(){ int valor, suma; cin >> valor; for ( ; valor!=0 ; ){ suma = suma + valor cin >> valor; }

Estructuras de Control Estructuras repetitivas Particularidades de C++

204

II.2.4.3.

Otras (perniciosas) estructuras de control

Existen otras sentencias en la mayora de los lenguajes que permiten alterar el ujo normal de un programa. En concreto, en C++ existen las siguientes sentencias:

goto

continue

break

exit

Durante los 60, qued claro que el uso incontrolado de sentencias de transferencia de control era la principal fuente de problemas para los grupos de desarrollo de software. Fundamentalmente, el responsable de este problema era la sentencia goto que le permite al programador transferir el ujo de control a cualquier punto del programa. Esta sentencia aumenta considerablemente la complejidad tanto en la legibilidad como en la depuracin del cdigo.
Referencias: Teorema de Bohm y Jacopini -1966-. Flow diagrams, Turing machines and languages only with two formation rules. Communications of the ACM, 1966. Vol. 9, No.5, pp. 366-371 Dijkstra, E.W. Goto statement considered harmful. Communications of the ACM, 1968. Vol. 11, No.3, pp. 147-148

Estructuras de Control Estructuras repetitivas Particularidades de C++

205

Ampliacin:
Consultad el libro Code Complete de McConnell, disponible en la biblioteca. Incluye numerosos consejos y hbitos aconsejables de programacin. En el tema de Estructuras de Control incluye una referencia a un informe en el que se reconoce que un uso inadecuado de un break, provoc un apagn telefnico de varias horas en los 90 en NY.

En FP, no se permitir el uso de ninguna de las sentencias anteriores, excepto la sentencia break con el propsito aqu descrito dentro de la sentencia switch. En caso contrario, el Suspenso est garantizado.

Bibliografa recomendada para este tema: A un nivel menor del presentado en las transparencias: Segundo captulo de Deitel & Deitel A un nivel similar al presentado en las transparencias: Segundo y tercer captulos de Garrido. A un nivel con ms detalles: Captulos quinto y sexto de Stephen Prata. Tercer captulo de Lafore. Los autores anteriores presentan primero los bucles junto con la expresiones lgicas y luego los condicionales.

ndice alfabtico
algoritmo (algorithm), 6 aviso (warning), 52 biblioteca (library), 13 bit, 44 bucle controlado por condicin (condition-controlled loop), 142 bucle controlado por contador (counter controlled loop), 142 bucle post-test (post-test loop), 142 bucle pre-test (pre-test loop), 142 byte, 44 cdigo binario (binary code), 3 cdigo fuente (source code), 11 cadena de caracteres (string), 78 capas (layers), 123 carcter (char), 69 coma otante (oating point), 55 componentes lxicos (tokens), 19 condicin (condition), 91 constante (constant), 31 criptografa (cryptography), 185 dato (data), 6, 26 datos (data), 14 desbordamiento aritmtico (arithmetic overow), 52 diagramas de ujo (owchart), 97 errores en tiempo de compilacin (compilation error), 22 errores en tiempo de ejecucin (execution error), 23 errores lgicos (logic errors), 23 estructura condicional (conditional structure), 91 estructura repetitiva (iteration/loop), 142 estructura secuencial (sequential control ow structure), 91 evaluacin en ciclo corto (shortcircuit evaluation), 135 evaluacin en ciclo largo (eager evaluation), 135 exponente (exponent), 55 expresin (expression), 41 expresiones aritmticas (arithmetic expression), 62 ltro (lter), 144 ujo de control (control ow), 20 funcin (function), 39

hardware, 2

operador binario (binary operator), 38 identicador (name), 26 operador n-ario (n-ary operator), 38 implementacin de un algoritmo (aloperador unario (unary operator), gorithm implementation), 9 38 indeterminacin (undened), 59 palabra (word), 45 innito (innity), 59 parmetros (parameter), 39 iteracin (iteration), 143 principio de programacin - sencilgico (boolean), 81 llez (programming principle lenguaje de programacin (prosimplicity), 163 gramming language), 2, 3 principio de programacin - una lenguaje ensamblador (assembly nica vez (programming prinlanguage), 4 ciple - once and only once), 64 lenguajes de alto nivel (high level programa (program), 3 language), 4 programador (programmer), 2 literal (literal), 46 literales de cadenas de caracteres rango (range), 43 real (oat), 54 (string literals), 28 literales de caracteres (character li- reglas sintcticas (syntactic rules), 19 terals), 28 literales enteros (integer literals), 46 sentencia condicional (conditional literales lgicos (boolean literals), statement), 91 28 sentencias (sentence/statement), literales numricos (numeric lite13 rals), 28 sniffers, 185 mquina de turing (turing machine), software, 2 10 tipo de dato (data type), 26 mantisa (mantissa), 55 tipo enumerado (enumerated type), 88 niveles (tiers), 123 transformacin de tipo (casting), 66 notacin inja (inx notation), 38 notacin preja (prex notation), 38 usuario (user), 2 operador (operator), 39 valor (value), 26

Вам также может понравиться