Índice general 1.1. Introducción a la programación……………..................................03 1.1.1. El Ordenador: Conceptos Básicos. …..............................03 1.1.2. Algoritmos. . . . . . . . . . . . . . . . . . . ……………………..…05 1.1.3. Lenguajes de programación. . . . . . . …………………….. 06 1.1.4. Programas. . . . . . . . . . . . . . …... . . ……….……………...08 1.2. Especificación de programas ……………….................................10 1.2.1. Escritura y organización de un programa... …………........10 1.2.2. Elementos básicos de un lenguaje de programación … 13 1.2.2.1. Tokens y reglas sintácticas ……………….. . . ………….13 1.2.2.2. Palabras reservadas. . . . . . . ……………………..........14 1.2.3. Tipos de errores en la programación. programación . …. ……………. 15 1.3. Datos, tipos de datos y literales . . . . . …… . . . . ………….. 16 1.3.1. Representación en memoria de datos e instrucciones. ….16 1.3.2. Datos y tipos de datos. . . . . . . . …. . . . ……………………….. 17 1.3.2.1. Literales. Literales. . . . . . . . . . . . . . . ……………………………..18 1.3.2.2. Declaración Declaración de datos. . . . . . . …………………………. 18 1.3.2.3. Datos Datos constantes. . . . . . . . . . …………………………. 19 1.3.2.4. Normas para la elección del identificador . . . . . . . ......20 1.4. Operadores y Expresiones. . . . . . . . ………. . . . ……………….. 21 1.4.1. Terminología en Matemáticas. Matemáticas. . . . . . . . ……………….. 21 1.4.2. Operadores en un lenguaje de programación …………..21 1.4.3. Expresiones. Expresiones. . . . . . . . . . . . . . . . . . …………………….. 22 1.5. Tipos de datos comunes en C++ . . . . . . . …….. . ………….. … 22 1.5.1. Rango y operadores aplicables a un tipo de dato …...... 22 1.5.2. Los tipos tipos de datos enteros. enteros. . . . . . . . . …………..……... .23 1.5.2.1. Rango de los enteros. . . . . . . …………………………..23 1.5.2.2. Operadores. Operadores. . . . . . . . . . . . . ……………………………. 23 1.5.3. Los tipos de datos reales. . . . . . . . . . …………………………...25 1.5.3.1. Rango. . . . . . . . . . . . . . . . ……………………………… 25 1.5.3.2. Operadores. Operadores. . . . . . . . . . . . . ……………………………. 24 1.5.3.3. Funciones estándar. estándar. . . . . ... . ……………………………26 1.5.3.4. Expresiones Expresiones reales. . . . . . . . . …………………………..26 1.5.4. Operaciones con tipos numéricos distintos. …………………….26 1.5.5. El tipo de dato carácter. . .. ……. . . . . . . ……………………… 27 1.5.5.1. Rango. . . . . . . . . . . . . . . . ………………………………27 1.5.5.2. Funciones estándar. estándar. . . . . . . . ……………………………28 1.5.6. El tipo de dato cadena de caracteres…………………… . . …...28 Programación I
1
UCENM
1.5.7 El tipo de dato lógico o booleano……………………… . . ……..29 1.5.7.1. rango……………………………………….…………. . …...29 1.5.7.2. operadores……………………………….………… . . …......29 1.5.7.3. operadores relacionales ……………….…………. . …......30 2.2. Estructura Condicional Condicional . . . . . . . . . . . . . . . . ………………………32 2.2.1. Introducción Introducción . . . . . . . . . . . . . . . . . . ………………………...34 2.2.2. Estructura Estructura Condicional Simple . . . . . . . ……………………34 2.2.3. Una notación para describir algoritmos …………………….35 2.2.4. Condicional Condicional Doble . . . . . . . . . . . . . . ……………………….37 2.2.5. Anidamiento de Estructuras Condicionales ……………….. 39 2.2.6. Estructura Condicional Condicional Múltiple . . . . . . ……………………..45 2.2.7. Cuestiones adicionales . . . . . . . . . . . ……………………….47 2.2.7.1. Evaluación Evaluación en ciclo corto y en ciclo largo .. . . . . . . . . . ,. 47 2.2.7.2. Particularidades de C++ . ………………………………. . .47 2.3. Estructuras Repetitivas .. . ……………………… . . . . . . . . . . …. 47 2.3.1. Bucles controlados por condición: pre-test y post-test . . ..48 2.3.1.1. Formato . . . . . . . . . . . . . . . ……………………………….48 2.3.1.2. Lectura Lectura Anticipada . . . . . . . . . …………………………... 52 2.3.1.3. Bucles sin fín . . . . . . . . . . . . …………………………….. 54 2.3.1.4. Creación de filtros con ciclos posttest . . . . . . . . . . . . . . 54 2.3.1.5. Bucles controlados por contador ………………………….54 2.3.2. Bucle for como bucle controlado controlado por contador. . . . . . . . . . 56 2.3.2.1. Formato . . . . . . . . . . . . …………………………………… 56 2.3.2.2. Algunas Aplicaciones . . . ……………………………. …… 58 2.3.2.3. Criterio de uso de bucle for. ………………………………. 59 2.3.2.4. Bucles for con sentencias vacías …………………………..60 2.3.2.5. El bucle for como ciclo controlado por condición . . . . . . 60 2.3.3. Anidamiento de bucles bucles . . . . . . . . …………………………. . …. 64 3.1. ejercicios propuestos ……………………………………………...68 Guia practica Capitulo I…………………………………………………..71 Bibliografía………………………………………………………………….96
Programación I
2
UCENM
1.5.7 El tipo de dato lógico o booleano……………………… . . ……..29 1.5.7.1. rango……………………………………….…………. . …...29 1.5.7.2. operadores……………………………….………… . . …......29 1.5.7.3. operadores relacionales ……………….…………. . …......30 2.2. Estructura Condicional Condicional . . . . . . . . . . . . . . . . ………………………32 2.2.1. Introducción Introducción . . . . . . . . . . . . . . . . . . ………………………...34 2.2.2. Estructura Estructura Condicional Simple . . . . . . . ……………………34 2.2.3. Una notación para describir algoritmos …………………….35 2.2.4. Condicional Condicional Doble . . . . . . . . . . . . . . ……………………….37 2.2.5. Anidamiento de Estructuras Condicionales ……………….. 39 2.2.6. Estructura Condicional Condicional Múltiple . . . . . . ……………………..45 2.2.7. Cuestiones adicionales . . . . . . . . . . . ……………………….47 2.2.7.1. Evaluación Evaluación en ciclo corto y en ciclo largo .. . . . . . . . . . ,. 47 2.2.7.2. Particularidades de C++ . ………………………………. . .47 2.3. Estructuras Repetitivas .. . ……………………… . . . . . . . . . . …. 47 2.3.1. Bucles controlados por condición: pre-test y post-test . . ..48 2.3.1.1. Formato . . . . . . . . . . . . . . . ……………………………….48 2.3.1.2. Lectura Lectura Anticipada . . . . . . . . . …………………………... 52 2.3.1.3. Bucles sin fín . . . . . . . . . . . . …………………………….. 54 2.3.1.4. Creación de filtros con ciclos posttest . . . . . . . . . . . . . . 54 2.3.1.5. Bucles controlados por contador ………………………….54 2.3.2. Bucle for como bucle controlado controlado por contador. . . . . . . . . . 56 2.3.2.1. Formato . . . . . . . . . . . . …………………………………… 56 2.3.2.2. Algunas Aplicaciones . . . ……………………………. …… 58 2.3.2.3. Criterio de uso de bucle for. ………………………………. 59 2.3.2.4. Bucles for con sentencias vacías …………………………..60 2.3.2.5. El bucle for como ciclo controlado por condición . . . . . . 60 2.3.3. Anidamiento de bucles bucles . . . . . . . . …………………………. . …. 64 3.1. ejercicios propuestos ……………………………………………...68 Guia practica Capitulo I…………………………………………………..71 Bibliografía………………………………………………………………….96
Programación I
2
UCENM
1.1. Introducción La principal razón para que las personas aprendan lenguajes y técnicas de programación es utilizar la computadora como una herramienta para resolver problemas. La resolución de problemas exige al menos los siguientes pasos 1. definición o análisis análisis del problema problema 2. diseño del algoritmo 3. transformación transformac ión del algoritmo en programa 4. ejecución y validación del programa Para la cual se hace hace necesaria enseñarle al al estudiante la introducción introducción a la programación, programación, que contemple contemple los conceptos conceptos básicos de algoritmo, estructura de datos y las técnicas de programación en un lenguaje, en nuestro casos c ++.
1.1.1. La computadora: CONCEPTOS BÁSICOS Los sistemas modernos de computación consisten en una gran conjunción de elementos de circuitos (hardware) y de programación (software) que han sido diseñados para proporcionar a la computación un ambiente productivo y hasta cierta medida agradable.
Programación I
3
UCENM
Componentes de un Sistema de Computación
•
La computadora : - dispositivo electrónico que procesa datos y los convierte en información útil para el usuario, siguiendo un programa de instrucciones
•
Hardware. – Dispositivos físicos que componen el ordenador: teclado, pantalla, ratón, discos, memoria, CD-ROM, unidades de procesamiento, etc.
•
Software
– Conjunto de programas que el ordenador puede ejecutar – El conjunto de instrucciones se llama programa – Cuando un ordenador usa un programa se dice que ejecuta el programa – Los dos tipos más comunes de software son: Software del sistema: Sistema operativo •
Programación I
4
UCENM
•
Software de aplicación: Hojas de cálculo, bases de
datos, etc •
Personas – Entretenimiento, medicina, educación, empresas, etc .
•
Datos e información dato representación de algún concepto o entidad real, pueden tomar diferentes formas por ejemplo palabra escrita , imagines, numero y sonidos - información implica datos procesados y organizados -
Programa:
•
- es simplemente una secuencia de instrucciones que orienta a la Unidad de Control de Procesamiento (CPU) en el desarrollo de los cálculos, el cual debe expresarse de forma que sea entendido por el CPU. Un CPU sólo puede entender instrucciones que estén expresadas en términos de su lenguaje máquina. •
Programador :persona encargada de desarrollar los algoritmos en el cualquier de los lenguajes existentes.
1.1.2. ALGORITMOS "Un algoritmo se define como un método que se realiza paso a paso para solucionar un problema que termina en un número finito de pasos". Podemos decir que es una secuencia ordenada de instrucciones que resuelve un problema concreto, atendiendo a las siguientes características básicas: •
•
•
Debe ser preciso. e indicar el orden de realización de cada paso.
Debe ser definido. Si se sigue un algoritmo dos veces, se debe obtener el mismo resultado cada vez. Debe ser finito. Si se sigue un algoritmo, se debe terminar en algún momento; o sea debe tener un número finito de pasos.
Programación I
5
UCENM
Usualmente, los algoritmos reciben unos datos de entrada con los que operan, y a veces, calculan unos nuevos datos de salida. Ejemplo 1.- Algoritmo de la media aritmética de N valores. 1. Sumar los N valores. 2. Dividir el resultado por N. Datos de entrada: los N valores. Datos de salida: la media. 2.- Diseñar un algoritmo para cambiar una llanta a un coche. 1. Inicio. 2. Traer gato. 3. Levantar el coche con el gato. 4. Aflojar tornillos de las llantas. 5. Sacar los tornillos de las llantas. 6. Quitar la llanta. 7. Poner la llanta de repuesto. 8. Poner los tornillos. 9. Apretar los tornillos. 10. Bajar el gato. 11. Fin Datos de entrada: la rueda pinchada, parches, pegamento, gata etc. Datos de salida: la rueda preparada . Dato auxiliar: las burbujas que salen donde esta el pinchazo.
1.1.3. LENGUAJES DE PROGRAMACIÓN Un algoritmo se describe utilizando algún lenguaje específico. Lenguaje natural: Es aquél que describe en español, para nuestro caso, los pasos a seguir utilizando un vocabulario cotidiano. Como los ejercicios anteriores Lenguaje de programación: Lenguaje utilizado para comunicarnos con un ordenador e imponerle la realización concreta de un conjunto de órdenes.
Programación I
6
UCENM
Algunos lenguajes de programación: 1. Lenguaje máquina. Son aquéllos que están escritos en lenguajes directamente entendibles por la máquina (computadora), ya que sus instrucciones son cadenas binarias ( cadenas o series de caracteres de dígitos 0 y 1) que especifican una operación y las posiciones (dirección) de memoria implicadas en la operación se denominan instrucciones de máquina o código máquina. El código máquina es el conocido código binario. Las instrucciones en lenguaje máquina dependen del hardware de la computadora y, por tanto, diferirán de una computadora a otra. 2. Lenguajes de alto nivel Son más fáciles de utilizar que los lenguajes máquina, pero al igual que ellos, dependen de la máquina en particular. El lenguaje de bajo nivel por excelencia es el ensamblador. Las instrucciones en lenguaje ensamblador son instrucciones conocidas como nemotécnicos. Por ejemplo, nemotécnicos típicos de operaciones aritméticas son: en inglés: ADD, SUB, DIV, etc. ; en español : SUM, RES, DIV, etc. Una instrucción típica de suma sería : ADD M, N, P Esta instrucción significa "sumar el contenido en la posición de memoria M al número almacenado en la posición de memoria N y situar el resultado en la posición de memoria P" . Evidentemente es más sencillo recordar la instrucción anterior con un nemotécnico que su equivalente en código máquina. 0110 1001 1010 1011 Un programa escrito en lenguaje ensamblador, requiere de una fase de traducción al lenguaje máquina para poder ser ejecutado directamente por la computadora. El programa original escrito en lenguaje ensamblador se denomina programa fuente y el programa traducido en lenguaje máquina se conoce como programa objeto, el cual ya es directamente entendible por la computadora.
Programación I
7
UCENM
1.1.4. PROGRAMAS
Programa: Es un conjunto de instrucciones escritas en un lenguaje de programación que indican a la computadora la secuencia de pasos para resolver un problema. Puede incluir uno o más algoritmo. EJEMPLO // Primer programa en C++ // Escribe en pantalla un mensaje #include
using namespace std; int main() { cout << "Bienvenido a C++" << endl; system("pause"); } Al código escrito en un lenguaje concreto se le denomina código fuente. Éste se guarda en ficheros de texto normales (en el caso de C++ suelen tener extensión .cpp). bienvenido.cpp es un simple fichero de texto. Para obtener el programa ejecutable (el fichero en binario que puede ejecutarse en un ordenador) a partir del código fuente, se utiliza un compilador :
Ejemplo no 2. –
Programación I
8
UCENM
// Programa que lee dos números enteros por teclado // y muestra por pantalla su división real #include using namespace std; int main() { int dato1; int dato2; double division; cout << "Introducir primer dato: "; cin >> dato1; cout << "Introducir segundo dato: "; cin >> dato2; if ( dato2 !=0 ) { division = (1.0*dato1) / dato2; cout << "La division es: " << division; } else cout << "Error: Division por cero" << endl; system("pause"); } Ejemplo no 3 / * Este programa solicita las longitudes de los lados de un triangulo y calcula su hipotenusa. */ #include #include using namespace std; int main(void) { double lado1, lado2, hipotenusa; //ENTRADAS
Programación I
9
UCENM
cout << "Este programa calcula la hipotenusa de un triangulo." << endl; cout << "Introduzca la longitud del lado 1: "; cin >> lado1; cout << "Introduzca la longitud del lado 2: "; cin >> lado2; //PROCESO hipotenusa = sqrt(lado1*lado1+lado2*lado2); //SALIDA cout << "La hiponusa es " << hipotenusa << endl; system("pause"); }
1.2. ESPECIFICACIÓN DE PROGRAMAS 1.2.1. ESCRITURA Y ORGANIZACIÓN DE UN PROGRAMA •
•
Los programas en C++ pueden dividirse en varios archivos aunque por ahora vamos a suponer que cada programa está escrito en un único fichero (por ejemplo , hipotemusa.cpp). Se pueden incluir comentarios en lenguaje natural. /* Comentario en varias líneas */
// Comentario 1 sola línea El texto de un comentario no es procesado por el compilador. Al principio del fichero se indica que vamos a usar una serie de recursos definidos en un fichero externo o biblioteca •
#include #include using namespace std; •
•
A continuación 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 que componen
Programación I
10
UCENM
el programa. Una sentencia es una parte del código fuente que el compilador puede traducir en una instrucción en código binario. •
•
•
Las sentencias van obligatoriamente separadas por punto y coma (;) El compilador va ejecutando las sentencias secuencialmente de arriba abajo. 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 declaración de datos . double lado1, lado2; // <- Separados por coma double hip; // <- Pueden usarse varias líneas •
Declara tres datos (variables) de tipo real que el programador puede usar en el programa. Cada dato que se use en un programa debe declararse al principio (después de main), asociándole un tipo de dato concreto. •
Sentencias de cálculo, a través de la asignación = lado1 = 7; lado2 = 5; hip = sqrt(lado1*lado1 + lado2*lado2); asigna a la variable hip el resultado de evaluar lo que aparece a la derecha de la asignación .
•
Sentencias para mostrar información en el periférico de salida establecido por defecto . Dicho periférico será la pantalla, pero podría ser un archivo en disco o dispositivo externo (impresora, plotter, puerto FireWire, etc .). Se construyen usando cout, que es un recurso externo incluido
Programación I
11
UCENM
en la biblioteca iostream. _ Lo que se vaya a imprimir va separado de cout por <<. _ 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 línea siguiente . _ Los números se escriben tal cual. cout << "Valor de Pi: " << 3.1415927; _ Si ponemos una variable, se imprime su contenido. cout << "Introduzca la longitud del primer cateto: "; ..... hip = sqrt(lado1*lado1+lado2*lado2); cout << "\nLa hipotenusa vale " << hip; _ Aunque no es recomendable, también pueden ponerse expresiones como: cout << "\nLa hipotenusa vale " << sqrt(lado1*lado1+lado2*lado2); •
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 . Su sintaxis más elemental es la siguiente 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 línea. Es una asignación en tiempo de ejecución Las entradas de datos deben etiquetarse adecuadamente: // MAL: cin >> lado1; Programación I
12
UCENM
cin >> lado2; // BIEN: cout << "Introduzca la longitud del primer cateto: "; cin >> lado1; cout << "Introduzca la longitud del segundo cateto: "; cin >> lado2; Estructura básica de un programa (los corchetes delimitan secciones opcionales):
1.2.2. Elementos básicos de un lenguaje de programación 1.2.2.1. tokens y reglas sintácticas Cada lenguaje de programación tiene una sintaxis propia que debe respetarse para poder escribir un programa. Básicamente, queda definida por :
a) Los componentes léxicos o tokens. Un token es un carácter o grupo de caracteres alfanuméricos o simbólicos que representa la unidad léxica mínima que el lenguaje entiende. Por ejemplo: main ; { double hip * Programación I
13
UCENM
b) Reglas sintácticas que determinan como han de combinarse los tokens para formar sentencias. Algunas reglas sintácticas se especifican con tokens especiales (formados usualmente por símbolos): o Separador de sentencias ; o Para agrupar varias sentencias se usa { } o Para agrupar expresiones (fórmulas) se usa ( ) hip = sqrt((lado1*lado1)+(lado2*lado2)); 1.2.2.2. PALABRAS RESERVADAS Suelen ser tokens formados por caracteres alfabéticos. Tienen un significado específico para el compilador, y por tanto, el programador no puede definir variables con el mismo identificador. Algunos usos: main Para definir tipos de datos como por ejemplo double Para establecer el flujo de control , es decir, para especificar el orden en el que se han de ejecutar las sentencias, como if , while, for etc. // Errores sintácticos • •
•
int main(){ double main; // main es un nombre de dato incorrecto double double; // double es un nombre de dato incorrecto }
Palabras reservadas comunes a C (C89) y C++
Programación I
14
UCENM
•
1.2.3. TIPOS DE ERRORES EN LA PROGRAMACIÓN Errores en tiempo de compilación. Ocasionados por un fallo de sintaxis en el código fuente. No se genera el programa ejecutable . /* CONTIENE ERRORES */ #include USING namespace std; int main{}( double la do1, lado2, hip: lado1 = 2; lado2 = 3 hip = sqrt(lado1**lado1 + ladp2*ladp2); cout << "La hipotenusa vale << hip;
) Errores en tiempo de ejecución. Se ha generado el programa ejecutable, pero se produce un error durante la ejecución . •
......... Programación I
15
UCENM
lado1 = 9; lado2 = 4; hip = sqrt(-lado1*lado1-lado2*lado2); variable = 0; dato = 10 / variable; ......... •
Errores lógicos Se ha generado el programa ejecutable, pero el programa ofrece una solución equivocada . ......... lado1 = 4; lado2 = 9; hip = sqrt(lado1+lado1+lado2*lado2); ......... 1.3. DATOS, TIPOS DE DATOS Y LITERALES
1.3.1. REPRESENTACIÓN 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.
Programación I
16
UCENM
1.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 codifican un valor concreto, sino a lo que representa para nosotros. Un dato es un conjunto de celdas o posiciones de memoria que tiene asociado un nombre ( identificador ) y un contenido (valor ). NombreEmpleado "Juan Pérez " NúmeroHabitantes 75.225.813 Pi 3.14159 El compilador reconoce distintas categorías de datos (numéricas, texto, etc.). Necesitamos almacenar muchos tipos de información (enteros, reales, caracteres, cadenas de caracteres,etc.). Para cada tipo, el lenguaje ofrece un tipo de dato. Por ejemplo, en C++:
Programación I
17
UCENM
1.3.2.1. LITERALES Son la especificación de un valor concreto de un tipo de dato. Dependiendo del tipo, tenemos: Literales numéricos: son tokens numéricos. Para representar datos reales, se usa el punto. Para especificar la parte decimal: 2 3 3.5 Literales de caracteres: Es un único carácter encerrado entre comillas simples: 'a' Literales de cadenas de caracteres: Son cero o más caracteres encerrados entre comillas dobles : "Hola" Literales lógicos : true para representar verdadero y false para falso. •
•
•
•
1.3.2.2. DECLARACIÓN DE DATOS Cada dato que se use en un programa debe declararse al principio (después de main), asociándole un tipo de dato concreto y un identificador. Al declarar un dato, el compilador reserva una zona de memoria para trabajar con él. Ningún otro dato podrá usar dicha zona. Cada dato debe estar asociado a un único tipo de dato (el tipo no puede cambiarse durante la ejecución). El valor que se le puede asignar a un dato depende del tipo de dato con el que es declarado. Los datos se pueden clasificar como: datos : variables y constantes •
•
•
•
•
Las variables con datos cuyo valor puede variar a lo largo del programa, p.e ., lado1. Las constantes son datos cuyo contenido no varía a lo largo de la ejecución del programa, p.e ., el número
Declaración de variables : •
Un único identificador por declaración : ; ;
Programación I
18
UCENM
...
•
Ejemplo: double lado1; double lado2; double hip; Varios identificadores por declaración : ; Ejemplo: double lado1, lado2, hip; Opcionalmente, se puede dar un valor inicial durante la declaración: = ; = , ...; Ejemplo: double dato = 4.5; int sumaCuentas = 0, totalVentas;
Cuando se declara una variable y no se inicializa, ésta no tiene ningún valor asignado por defecto. Puesto que desconocemos su valor, lo podremos considerar como basura, y lo representaremos gráficamente por ?. 1.3.2.3. DATOS CONSTANTES Si sólo permitimos un único valor para un dato, usaremos una constante. Se declaran como sigue: const = ; Suelen usarse identificadores sólo con mayúsculas para diferenciarlos de los datos variables . Una sintaxis de programa algo más completa
Programación I
19
UCENM
1.3.2.4. NORMAS PARA LA ELECCIÓN DEL IDENTIFICADOR Cada dato necesita un identificador único. Un identificador de un dato es un token formado por caracteres alfanuméricos 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 eñe, las barras \ o /, etc. Ejemplo: lado1 lado2 precio_con_IVA El compilador determina la máxima longitud que pueden tener (por ejemplo, 31 caracteres) Sensibles a mayúsculas y minúsculas . lado y Lado son dos identificadores distintos. No se podrá dar a un dato el nombre de una palabra reservada. No es recomendable usar el nombre de algún identificador usado en las bibliotecas estándar (por ejemplo, cout) • •
•
•
•
Programación I
20
UCENM
1.4. Operadores y Expresiones 1.4.1. TERMINOLOGÍA EN MATEMÁTICAS Notaciones usadas en los operadores : Prefija. El operador va antes de los argumentos. Estos suelen encerrarse entre paréntesis. seno(3), tangente(x), media(valor1, valor2) •
Infija. El operador va entre los argumentos . 3+5 x / y Según el número de argumentos, diremos que un operador es: Unario. Sólo tiene un argumento : seno(3), tangente(x) Binario. Tienes dos argumentos: media(valor1, valor2) 3+5 x/y n-ario. Tiene más de dos argumentos. •
• • •
1.4.2. OPERADORES EN UN LENGUAJE DE PROGRAMACIÓN
Al igual que en Matemáticas, los operadores realizan una acción específica. Suelen devolver un valor . Los operadores operan sobre los datos (variables o constantes), literales y sobre el resultado que dan otros operadores . Ejemplos: + (suma), - (resta), * (producto), etc. int main() { const double PI = 3.1415926; double area, radio; cout << "Introduzca el valor del radio "; cin >> radio; area = PI * radio * radio; • •
La asignación es otro operador (infijo y binario). En primer lugar, se evalúa el argumento de la derecha y se asigna el resultado al dato (variable) de la izquierda . lado = 3 + 5;
Programación I
21
UCENM
1.4.3. EXPRESIONES Una expresión es una combinación de datos y operadores sintácticamente correcta, que el compilador evalúa 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 asignación, pero no a la izquierda. También pueden pasarse como argumentos de operadores . Una expresión NO es una sentencia de un programa: Expresión: sqrt(lado1*lado1 + lado2*lado2) Sentencia: hip = sqrt(lado1*lado1 + lado2*lado2) 1.5. TIPOS DE DATOS COMUNES EN C++ 1.5.1. RANGO Y OPERADORES APLICABLES A UN TIPO DE DATO Las características que definen el comportamiento de un tipo de dato son: El rango de valores que puede representar, que depende de la cantidad de memoria que dedique el compilador a su representación interna. Intuitivamente, cuanta más memoria se dedique para un tipo de dato, mayor será el número de valores que podremos representar. La forma de hacerlo (codificación en binario) se ve en otras asignaturas. La cantidad de memoria que el compilador asigna a cada tipo se puede consultar mediante la operación sizeof() cuyo resultado es un entero que contiene el número de bytes asignados a . Los valores mínimos y máximos que se pueden representar para cada tipo se pueden consultar en los ficheros climits y cfloat El conjunto de operadores que pueden aplicarse a los datos de ese tipo. •
•
•
Programación I
22
UCENM
1.5.2. LOS TIPOS DE DATOS ENTEROS 1.5.2.1. RANGO DE LOS ENTEROS Subconjunto del conjunto matemático Z. La cardinalidad dependerá del número de bytes que cada compilador utiliza para su almacenamiento. Cuanta más memoria, más datos distintos podrán representarse . Los compiladores suelen ofrecer distintos tipos enteros. En C(C++): int, long, short , etc. Por simplificar, usaremos un único tipo entero : int Literales enteros Los literales son la especificación de un valor concreto de un tipo de dato. Los literales enteros son tokens formados por símbolos numéricos. Pueden empezar con un signo negativo 34 -406778 0
1.5.2.2. OPERADORES Operadores binarios + - * / % suma, resta, producto, división entera y módulo. Devuelven un entero. Binarios. Notación infija: a*b int n; n = 5 * 7; // Asigna a la variable n el valor 35 n = n + 1; // Asigna a la variable n el valor 36 n = 5 / 7; // Asigna a la variable n el valor 0 5 / 7 = n; // Sentencia Incorrecta. 5 / 7; // Sentencia Incorrecta.
Programación I
23
UCENM
El operador módulo (%) representa el resto de la división entera int a, b, cociente, resto; a = 10; b = 3; cociente = a / b; // Asigna a cociente el valor 3 resto = a % b; // Asigna a resto el valor 1 b = 7 / 5; // Asigna a b el valor 1 Operadores unarios de incremento y decremento
++ y --
Incrementan y decrementan, respectivamente, el valor de la variable entera sobre la que se aplican (no pueden aplicarse sobre una expresión). Unarios de notación postfija . ++; /* Incrementa la variable en 1 Es equivalente a: = + 1; */ --; /* Decrementa la variable en 1 Es equivalente a: = - 1; */ ------------------------------------------------int dato=4, aux1, aux2; dato = dato+1; // Asigna 5 a dato aux1 = dato; // Asigna 5 a aux1 dato++; // Asigna 6 a dato aux2 = dato; // Asigna 6 a aux2
-------------------------------------------------------Operador unario de cambio de signo Cambia el signo de la variable sobre la que se aplica. Unario de notación prefija. int dato=4, aux1, aux2; aux1 = -dato; // Asigna -4 a aux1 aux1 = -aux1; // Asigna 4 a aux1
Programación I
24
UCENM
1.5.3. LOS TIPOS DE DATOS REALES 1.5.3.1. RANGO Subconjunto finito de R Parte entera de 4;56 = 4 Parte real de 4;56 = 56 La precisión de un tipo real puede definirse como la diferencia entre 1,0 y el siguiente número que se puede representar. En Matemáticas, R es denso, por lo que la precisión es infinita. En cualquier lenguaje de programación los reales tendrán una precisión limitada, que dependerá de la cantidad de memoria utilizada para representar la parte decimal . Por ejemplo, si la precisión es 0;001, el valor 0;0003 no podría representarse. Los compiladores suelen ofrecer distintos tipos reales. Por ejemplo, en C(C++): float, double Por simplificar, usaremos un único tipo real: double En aplicaciones reales habrá que escoger el tipo adecuado dependiendo de lo que representa. • •
Literales reales Son tokens formados por dígitos numéricos y con un único punto que separa la parte decimal de la real . Pueden llevar el signo - al principio . 800.457 4.0 -3444.5 También se puede utilizar notación científica: 3e-5 que representa el valor 3 _ 10_5 = 0;00001
1.5.3.2. OPERADORES +, -, *, / Binarios, de notación infija. También se puede usar el operador unario de cambio de signo (-) Aplicados sobre reales, devuelven un real. double r;
Programación I
25
UCENM
r = 5.0 * 7.0; // Asigna a r el valor 35.0 r = 5.0 / 7.0; // Asigna a r el valor 0.7142857 ¡Cuidado! El comportamiento del operador / depende del tipo de los operandos: si todos son enteros, es la división entera. Si todos son reales, es la división real. 1.5.3.3. FUNCIONES ESTÁNDAR Hay algunas bibliotecas estándar que proporcionan funciones que trabajan sobre datos numéricos (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 #include using namespace std; int main() { double real, r; real = 5.4; r = sqrt(real); r = pow(real,real); } 1.5.3.4. EXPRESIONES REALES Son expresiones cuyo resultado es un número real. En general, diremos que las expresiones aritméticas o numéricas son aquellas expresiones bien enteras, bien reales . double a, x, y, c, resultado; resultado = x - sqrt(sqrt(a)-a*c))/(x-y); 1.5.4. OPERACIONES CON TIPOS NUMÉRICOS DISTINTOS Muchos operadores numéricos permiten como argumentos, expresiones de tipos distintos. double r; r = 5.0 * 7.0; // Asigna a r el valor 35.0
Programación I
26
UCENM
r = 5.0 / 7.0; // Asigna a r el valor 0.7142857 r = 5.0 / 7; // Asigna a r el valor 0.7142857 r = 5 / 7; // Asigna a r el valor 0 Para evaluar una expresión 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 asignación también lo permite: double real; int entero = 5; real = 5; // double = int real = entero // double = int 1.5.5. EL TIPO DE DATO CARÁCTER 1.5.5.1. RANGO Es un conjunto finito y ordenado de caracteres: letras minúsculas , mayúsculas, dígitos del 0 al 9 y otros caracteres especiales . Hay varios tipos de dato de carácter: char, wchar, signed char , etc. usaremos char . secuencia de escape,
Programación I
27
UCENM
1.5.5.2. FUNCIONES ESTÁNDAR El fichero de cabecera cctype contiene varias funciones relativas a caracteres. Por ejemplo: tolower toupper #include using namespace std; int main(){ char car; car = tolower('A'); // Almacena 'a' car = toupper('A'); // Almacena 'A' car = tolower('B'); // Almacena 'b' car = tolower('?'); // Almacena '?' .................. 1.5.6. EL TIPO DE DATO CADENA DE CARACTERES Los literales de cadenas de caracteres son una sucesión de caracteres encerrados entre comillas dobles : "Hola", "a" son literales de cadena de caracteres cout << "Esto es un literal de cadena de caracteres"; Hay que destacar que las secuencias de escape también pueden aparecer en los literales de cadena de caracteres presentes en cout int main(){ cout << "Bienvenidos"; cout << "\nEmpiezo a escribir en la siguiente línea"; cout << "\n\tAcabo de tabular esta línea"; cout << "\n"; cout << "\nEsto es una comilla simple '"; cout << " y esto es una comilla doble \""; } Escribiría en pantalla : Bienvenidos Empiezo a escribir en la siguiente línea Acabo de tabular esta línea Esto es una comilla simple ' y esto es una comilla doble "
Programación I
28
UCENM
El tipo de dato para declarar estos datos es string int main(){ string mensaje_bienvenida; mensaje_bienvenida = "\tCubero Corporation\n"; cout << mensaje_bienvenida; ........ } Los operadores para string trabajan con una sintaxis distinta a la que sabemos. #include using namespace std; int main(){ string cad; cad = "Hola y "; cad.append("adiós"); cout << cad; ..... 1.5.7. EL TIPO DE DATO LÓGICO O BOOLEANO Es un tipo de dato muy común en los lenguajes de programación que se utiliza para representar los valores verdadero y falso que suelen estar asociados a una condición. En C++ se usa el tipo bool 1.5.7.1. RANGO Un dato lógico, sólo puede tomar dos valores : true (verdadero) y false (falso). Una expresión lógica es una expresión cuyo resultado es un tipo de dato lógico .
1.5.7.2. OPERADORES Son los operadores clásicos de la lógica NO, Y, O que en C++ son los operadores !, &&, ||, respectivamente .
Programación I
29
UCENM
Muchas funciones de cctpye devuelven un valor lógico Isalpha isalnum isdigit ... Por ejemplo, isalpha('3') es una expresión lógica (devuelve false) /* Ejemplo de tipo de dato lógico (bool) */ #include 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); // Resultado: false compuesto = (es_alfa || es_alfanum); // Resultado: true compuesto = !es_alfa; // Resultado: true ....... } 1.5.7.3. OPERADORES RELACIONALES Son los operadores habituales de comparación de expresiones numéricas. Pueden aplicarse a operandos tanto enteros, reales, como de caracteres y tienen el mismo sentido que en Matemáticas. Programación I
30
UCENM
El resultado es de tipo bool. == (igual), != (distinto), <, >, <= (menor o igual) y >= (mayor o igual) La expresión (4 < 5) devuelve valor true La expresión (4 > 5) devuelve el valor false Nota: != es el operador relacional distinto . ! es la negación lógica . == es el operador relacional de igualdad . = es la operación de asignación . Tanto en == como en != se usan 2 signos para un único operador // Ejemplo de operadores relacionales int main(){ int entero1 = 3, entero2 = 5; double real1, real2; bool menor, iguales; menor = entero1 < entero2; menor = entero2 < entero1; menor = (entero1 < entero2) && !(entero2 < 7); real1 = 3.8; real2 = 8.1; menor = real1 > entero1; menor = !menor && (real1 > real2); iguales = real1 == real2; } Veremos su uso en la sentencia condicional : if (4 < 5) cout << "4 es menor que 5"; if (!(4 > 5)) cout << "4 es menor o igual que 5"; Nota. Cuidado cuando se comparan reales. La expresión 1.0e15 == (1.0/3.0)*3.0*1.0e15 podría evaluarse a false debido a problemas de precisión . Reglas de Precedencia: () ! Programación I
31
UCENM
< <= > >= == != && || A es menor o igual que B y B no es mayor que C A <= B && !B > C MAL (A <= B) && (!(B > C)) BIEN (A <= B) && !(B > C) RECOMENDADO 2.2. ESTRUCTURA CONDICIONAL 2.2.1. INTRODUCCIÓN Los elementos básicos que integran un programa o algoritmo son: Palabra reservada Constantes Variables Expresiones Instrucciones Adema de estos elementos básicos existen otros elementos que forman parte de los programas, cuya comprensión será vital para el correcto diseño de un algoritmo y la codificación del programaba. Estos elementos son Bucles Contadores Acumuladores Interruptores Estructuras o Secuenciales o Selectivas o Repetitivas El conocimiento de todos estos elementos de programación y el modo de su integración en los programas constituyen las técnicas de programación que todo buen programador debe conocer.
La ejecución de una estructura condicional consiste en la ejecución de una (o más) sentencia(s) dependiendo de la evaluación de una condición. Una estructura condicional es una estructura que permite una Ejecución condicional. Existen tres tipos: Simple, Doble y Múltiple. Programación I
32
UCENM
Ejemplo: Calcular las raíces de una ecuación de 2o grado . Algoritmo: Entradas: Los parámetros de la ecuación a, b, c. Salidas: Las raíces de la parábola r1, r2 Descripción: Calcular r1, r2 en la forma siguiente:
/* Programa que calcula las raíces de una ecuación de segundo grado (primera versión ) */ #include #include using namespace std; int main(){ double a, b, c; // Parámetros de la ecuación double r1, r2; // Raíces obtenidas 1 cout << "\nIntroduce coeficiente de 2o grado: "; 2 cin >> a; 3 cout << "\nIntroduce coeficiente de 1er grado: "; 4 cin >> b; 5 cout << "\nIntroduce coeficiente independiente: "; 6 cin >> c; 7 r1 = ( -b + sqrt( b*b-4*a*c ) ) / (2*a); 8 r2 = ( -b - sqrt( b*b-4*a*c ) ) / (2*a); 9 cout << "Las raíces son" << r1 << " y " << r2 << endl; } Flujo de control : (1,2,3,4,5,6,7,8,9) Pregunta: ¿Es a distinto de cero? – Si. Entonces sigue la ejecución. Programación I
33
UCENM
– No. Entonces salta las sentencias 7 –9 y termina.
/* Programa que calcula las raíces de una ecuación de segundo grado (SEGUNDA VERSION ) */ #include #include using namespace std; int main(){ double a, b, c; // Parámetros de la ecuación double r1, r2; // Raíces obtenidas 1 cout << "\nIntroduce coeficiente de 2o grado: "; 2 cin >> a; 3 cout << "\nIntroduce coeficiente de 1er grado: "; 4 cin >> b; 5 cout << "\nIntroduce coeficiente independiente: "; 6 cin >> c; 7 if (a!=0) { 8 r1 = ( -b + sqrt( b*b-4*a*c ) ) / (2*a); 9 r2 = ( -b - sqrt( b*b-4*a*c ) ) / (2*a); 10 cout << "Las raíces son" << r1 << " y " << r2 << endl; } } 2.2. ESTRUCTURA CONDICIONAL 2.2.1. INTRODUCCIÓN Una ejecución condicional consiste en la ejecución de una (o más) sentencia(s) dependiendo de la evaluación de una condición. Una estructura condicional es una estructura que permite una ejecución condicional. Existen tres tipos: Simple, Doble y Múltiple. 2.2.2. ESTRUCTURA CONDICIONAL SIMPLE if () es una expresión lógica es el bloque de ejecución condicional Programación I
34
UCENM
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) r1 = ( -b + sqrt( b*b-4*a*c ) ) / (2*a); r2 = ( -b - sqrt( b*b-4*a*c ) ) / (2*a); // :-( Error lógico) cout << "Las raíces son" << r1 << " y " << r2 << endl; 2.2.3. UNA NOTACIÓN PARA DESCRIBIR ALGORITMOS Diagramas de flujo Símbolos básicos
Símbolos adicionales
Programación I
35
UCENM
Programación I
36
UCENM
2.2.4. CONDICIONAL DOBLE
Programación I
37
UCENM
/* Programa que calcula las raíces de una ecuación de segundo grado (TERCERA VERSION ) */ #include #include using namespace std; int main(){ double a, b, c; // Parámetros de la ecuación double r1, r2; // Raíces obtenidas 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) { r1 = ( -b + sqrt( b*b-4*a*c ) ) / (2*a); r2 = ( -b - sqrt( b*b-4*a*c ) ) / (2*a); cout << "Las raíces son" << r1 << " y " << r2 << endl; } else { r1=-c/b; cout << "La única raíz es " << r1 << endl; } } Ejercicio. Identifica y corrige los errores de este código : if edad >= 65 cout << "Jubilado"; else; cout << "Poblacion activa" Ejemplo: El mayor de tres números a, b y c (primera versión ). Algoritmo: Entradas: a y b Salidas: El mayor entre a y b Descripción: Programación I
38
UCENM
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 if ((a>=b) && (a>=c)) max = a; if ((b>=a) && (b>=c)) max = b; if ((c>=a) && (c>=b)) max = c; cout << "El mayor es " << max << endl;
2.2.5. ANIDAMIENTO DE ESTRUCTURAS CONDICIONALES Dentro de un bloque if (else), puede incluirse otra estructura condicional, anidándose tanto como permita el compilador. Programación I
39
UCENM
if (condic_1) { inst_1; if (condic_2) { inst_2; } else { inst_3; } inst_4; } else { inst_5; } ¿Cuándo se ejecuta cada instrucción?
condic_1 condic_2 inst_1 true independiente inst_2 true true inst_3 true false inst_4 true independiente inst_5 false independiente Ejemplo: El mayor de tres números (segunda aproximación) Algoritmo: Entradas y Salidas: idem Descripción: Si a es mayor que b, entonces: Calcular el mayor entre a y c En otro caso, Calcular el mayor entre b y c if (a>=b) if (a>=c) max = a; else Programación I
40
UCENM
max = c; else if (b>=c) max = b; else max = c; cout << "El mayor es " << max << endl ;
Ejemplo: El mayor de tres números (tercera aproximación) Algoritmo: Entradas y Salidas: ídem Descripción: Calcular el máximo (max) entre a y b. Calcular el máximo entre max y c. if (a>=b) max = a; else max = b;
Programación I
41
UCENM
if (c>max) max = c; cout << "El mayor es " << max << endl;
¿Con qué algoritmo nos quedamos? Supongamos que todos los valores son distintos La solución 1 siempre evalúa 3 condiciones y realiza 1 asignación. La solución 2 siempre evalúa 2 condiciones y realiza 1 asignación. La solución 3 siempre evalúa 2 condiciones y realiza 1 ó 2 asignaciones. La solución 2 es más eficiente. eficiente. Pero la solución 3 es mucho mejor: Programación I
42
UCENM
Es mucho más fácil de entender Es mucho más fácil de extender a varios valores. El mayor de cuatro números. Aproximación 1: 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; cout << "El mayor es " << max << endl; Aproximación 2: 2: Algoritmo: Algoritmo: Entradas y Salidas: idem Descripción: Calcular el máximo (max) entre a y b. Calcular el máximo entre max y c. Calcular el máximo entre max y d.
Programación I
43
UCENM
if (a>=b) max = a; else max = b; if (c>max) max = c; if (d>max) max = d; cout << "El mayor es " << max << endl; En general: Calcular el máximo (max) entre a y b. Para cada uno de los valores restantes, calcular el máximo entre max y dicho valor . Ejemplo: Estructuras condicionales anidadas /* Programa que permite sumar o restar dos números enteros */ #include using namespace std; int main(){ int dato1, dato2; char opcion; cout << "\nIntroduce el primer operando: "; cin >> dato1; cout << "\nIntroduce el segundo operando: "; cin >> dato2; cout << "\nSelecciona (S) sumar, (R) restar: "; cin >> opcion; if (opcion == ’S’)
cout << "Suma = " << dato1+dato2 << endl; if (opcion == ’R’) cout << "Resta = " << dato1-dato2 << endl; if (opcion != ’R’ && opcion != ’S’)
Programación I
44
UCENM
cout << "Ninguna operación" << endl; } El mismo ejercicio pero más eficientemente : if (opcion == ’S’)
cout << "Suma = " << dato1+dato2 << endl; else if (opcion == ’R’) cout << "Resta = " << dato1-dato2 << endl; else cout << "Ninguna operación" << endl; } 2.2.6. ESTRUCTURA CONDICIONAL MÚLTIPLE
es un expresión entera . ó es un literal tipo entero o tipo carácter .
switch sólo comprueba la igualdad . No debe haber dos casos (case) con la misma en el mismo switch. Si esto ocurre, sólo se ejecutan las sentencias correspondientes al caso que aparezca primero .
Programación I
45
UCENM
El identificador especial default permite incluir un caso por defecto, que se ejecutará si no se cumple ningún otro . Se suele colocar como el último de los casos. En las estructuras condicionales múltiples también se permite el anidamiento.
Se usa frecuentemente en la construcción de menús: /* Programa que permite sumar o restar dos números enteros */ #include using namespace std; int main(){ int dato1,dato2; char opcion; cout << "\nIntroduce el primer operando: "; cin >> dato1; cout << "\nIntroduce el segundo operando: "; cin >> dato2; cout << "\nSelecciona (S) sumar, (R) restar: "; cin >> opcion; switch (opcion) { case ’S’: cout << "Suma = " << dato1+dato2 << endl;
break; case ’R’: cout << "Resta = " << dato1 -dato2 << endl;
break; default: cout << "Ninguna operación" << endl; } } Se pueden realizar las mismas operaciones para un grupo determinado de constantes : switch (opción) { case ’s’: case ’S’: cout << "Suma = " << dato1+dato2 << endl;
break; case ’r’: case ’R’: cout << "Resta = " << dato1 -dato2 << endl; Programación I
46
UCENM
break; default: cout << "Ninguna operación" << endl; break; // Ponemos break; aunque no sea necesario } 2.2.7. CUESTIONES ADICIONALES 2.2.7.1. EVALUACIÓN EN CICLO CORTO Y EN CICLO LARGO Evaluación en ciclo corto: El compilador optimiza la evaluación de expresiones lógicas evaluando sus términos de izquierda a derecha hasta que sabe el resultado de la expresión completa (lo que significa que puede dejar términos sin evaluar). La mayoría de los compiladores realizan este tipo de evaluación por defecto. Evaluación en ciclo largo: El compilador evalúa todos los términos de la expresión lógica para conocer el resultado de la expresión completa. Ejemplo:
if ( (a>0) && (b<0) && (c<1) ) ... Supongamos a = -3. Ciclo largo: El compilador evalúa (innecesariamente) todas las expresiones lógicas Ciclo corto: El compilador evalúa sólo la primera expresión lógica. 2.2.7.2. PARTICULARIDADES DE C++ En C++, el tipo lógico es compatible con un tipo entero. Cualquier expresión entera que devuelva el cero, se interpretará como false. Si devuelve cualquier valor distinto de cero, se interpretará como true.
2.3. ESTRUCTURAS REPETITIVAS Las estructuras repetitivas son también conocidas como bucles, Programación I
47
UCENM
ciclos o lazos. Una estructura repetitiva permite la ejecución de una secuencia de sentencias: o bien, hasta que se satisface una determinada condición (controladas por condición) o bien, un número determinado de veces (controladas por contador) 2.3.1. BUCLES CONTROLADOS POR CONDICIÓN: PRE-TEST Y POST-TEST 2.3.1.1. FORMATO
Funcionamiento: En ambos, se va ejecutando el cuerpo del bucle mientras la condición sea verdad. En un bucle while, primero se pregunta y luego (en su caso) se ejecuta. En un bucle do while, primero se ejecuta y luego se pregunta.
Programación I
48
UCENM
Elección Pre-test, o post-test: ¿Quiero que siempre se ejecute al menos una vez el cuerpo? Ejemplo: Escribir 20 líneas con 5 estrellas cada una . total = 1; do{ cout << "*****" << endl; total++; }while (total <= 20); O bien: total = 0; do{ cout << "*****" << endl; Programación I
49
UCENM
total++; }while (total < 20);
O bien: total = 1; while (total <= 20){ cout << "*****" << endl; total++; } O bien: total = 0; while (total < 20){ cout << "*****" << endl; total++; } Ejemplo: Leer un número positivo tope desde teclado e imprimir tope líneas con 5 estrellas cada una . cin >> tope; total = 0; do{ cout << "*****" << endl; total++; }while (total < tope); Problema: ¿Qué ocurre si tope = 0? Solución: cin >> tope; total = 0; while (total < tope){ cout << "*****" << endl; total++; }
Programación I
50
UCENM
Ejemplo: Leer un entero tope y escribir los pares _ tope
cin >> tope; par = 0; while (par<= tope){ par = par+2; cout << par; } Ejercicio. Calcular el máximo común divisor de dos números a y b. Probad con todos los enteros menores que el menor de ambos ambos números, hasta llegar al primero que divida a los dos. Algoritmo: Entradas: Los dos enteros a y b Salidas: el entero MCD de a y b Descripción: • Calcular el menor entre a y b • Probar con todos los enteros menores que menor , hasta encontrar uno que divida a ambos (a y b).
Ejemplo: // Programa que suma los valores leídos desde teclado // hasta que se introduzca el valor -1. #include using namespace std; int main(){ int suma, numero; suma = 0; do{ cin >> numero; suma = suma + numero; }while (numero != -1); cout << "La suma es " << suma << endl; } Programación I
51
UCENM
Problema: Procesa el ’-1’y lo suma. Solución: do{ cin >> numero; if (numero != -1) suma = suma + numero; }while (numero != -1); Funciona, pero evalúa dos veces la misma condición. Solución: técnica de lectura anticipada . 2.3.1.2. LECTURA ANTICIPADA Antes de entrar a un bucle pre-test, se comprueba el primer candidato. Ejemplo: // Programa que suma los valores leídos desde teclado // hasta que se introduzca el valor -1. // Usamos ciclo pre-test y lectura anticipada: #include using namespace std; int main(){ int suma, numero; suma = 0; cin >> numero; // Primer candidato while (numero != -1) { // ¿Es bueno? suma = suma + numero; cin >> numero; // Leer siguiente candidato } cout << "La suma es " << suma << endl; } Esta lectura anticipada nos permite ser más específicos con los mensajes en pantalla :
Programación I
52
UCENM
#include using namespace std; int main(){ int suma, numero; suma = 0; cout << "\nIntroduzca un valor entero\n" cout << "Para terminar introduzca -1"; cout << "\nValor: "; cin >> numero; // Primer candidato while (numero != -1) { // ¿Es bueno? suma = suma + numero; cout << "\nValor: "; cin >> numero; // Leer siguiente candidato } cout << "La suma es " << suma << endl; } Ejemplo: // Programa que va leyendo números enteros hasta que se // introduzca el cero. Imprimir el número de pares e // impares introducidos. #include using namespace std; int main(){ int ContPar, ContImpar, valor; ContPar=0; ContImpar=0; cout << "Introduce valor: " << endl; cin >> valor; while (valor != 0) { if (valor % 2 == 0) ContPar = ContPar + 1; else ContImpar = ContImpar + 1; cout << "Introduce valor: " << endl; cin >> valor; } cout << "Fueron " << ContPar << " pares y " << ContImpar << " impares" << endl; } Programación I
53
UCENM
2.3.1.3. BUCLES SIN FÍN Ejercicio:¿Cuantas iteraciones se producen? contador = 2; while (contador < 3) { contador--; cout << contador << endl; }
contador = 1; while (contador != 10) { contador = contador + 2; }
2.3.1.4. CREACIÓN DE FILTROS CON CICLOS POST-TEST Objetivo: Leer un valor y no permitir al usuario que lo introduzca fuera de un rango determinado. Una de las pocas veces que se usarán ciclos post-test. Ejemplo: // Introducir un único valor, pero positivo. // Imprimir el coseno. #include #include using namespace std; int main(){ int valor; do{ cout << "\nIntroduzca un valor positivo: "; cin >> valor; }while (valor < 0); cout << cos(valor); } Programación I
54
UCENM
2.3.1.5. BUCLES CONTROLADOS POR CONTADOR Se utilizan para repetir un conjunto de sentencias un número fijo de veces. Se necesita una variable controladora, un valor inicial, un valor final y un incremento. Ejemplo: Hallar la media aritmética de cinco enteros . // Hallar la media de 5 números enteros. #include using namespace std; int main(){ int i, valor, suma; double media; suma = 0; i = 1; // v_c = Vinic while (i <= 5){ // v_c <= Vfinal cout << "Introduce el número " << i << "o: \n"; cin >> valor; suma = suma + valor; i++; // v_c = v_c + 1 } media = suma / 5.0; cout << "La media es " << media << endl; }
Programación I
55
UCENM
Diagrama de flujo
v_c es la variable controladora del ciclo . Vinic valor inicial que toma v_c. Vfinal valor final que debe tomar v_c. 2.3.2. BUCLE for COMO BUCLE CONTROLADO POR CONTADOR 2.3.2.1. FORMATO La sentencia for permite la construcción de una forma compacta de los ciclos controlados por contador, aumentando la legibilidad del código . // Hallar la media de 5 números enteros. // Ejemplo de uso del for.
Programación I
56
UCENM
#include using namespace std; int main(){ int i, valor, suma; double media; suma = 0; for (i=1 ; i <= 5 ; i++){ cout << "Introduce el número " << i << "o: \n"; cin >> valor; suma = suma + valor; } media = suma / 5.0; cout << "La media es " << media << endl; }
Programación I
57
UCENM
asignación del valor inicial a la variable controladora del ciclo. v_c = Vinic determina el modo en que la variable controladora cambia su valor para la siguiente iteración. • Incrementos positivos: v_c = v _c + incremento • Incrementos negativos: v_c = v_c – incremento determina cuándo ha de continuar la ejecución del cuerpo del bucle. • v_c <= Vfinal ó bien v_c < Vfinal para incrementos positivos • v_c >= Vfinal ó bien v_c > Vfinal para increm entos negativos
Ejemplo: Imprimir 9 veces el mensaje Hola int i; for (i = 1; i <= 9; i++) cout << "Hola \n"; ¿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 condición del bucle sea falsa. Ejercicios: ¿Qué salida producen los siguientes trozos de código ? int i, j, total; total = 0; for(i=1 ; i<=10; i++) total = total + 3; cout << total << endl; numero 2 total = 0; for (i=4 ; i<=36 ; i=i+4) total++; ejercicio 3 Programación I
58
UCENM
total = 0; i = 4; while (i <= 36){ total++; i = i+4; } Encuentre errores en este código: For {x = 100, x>=1, x++} cout << x << endl; 2.3.2.3. CRITERIO DE USO DE BUCLE for Únicamente mirando la cabecera de un bucle for sabemos cuantas iteraciones se van a producir. Por eso, en los casos en los que sepamos de antemano cuantas iteraciones necesitamos, usaremos un bucle for . En otro caso, usaremos un bucle while ó do while. Para mantener dicha finalidad, es necesario respetar la siguiente restricción: No se debe modificar el valor de la variable controladora, ni el valor final dentro del cuerpo del bucle. Ejemplo. Sumar pares hasta un tope suma = 0; for (par=2; par<=tope ; par++){ if (par%2 == 0) suma = suma+valor; else par++; // :-( } Escribe los enteros entre inf y sup, hasta llegar al primer múltiplo de 13.
Programación I
59
UCENM
cin >> inf; cin >> sup; for (entero = inf; entero < sup; entero++) { cout << entero << endl; if (entero % 13 == 0) entero = sup; // :-( } Ejercicio. Haga el ejercicio anterior con un bucle while
2.3.2.4. BUCLES for CON SENTENCIAS VACÍAS ¿Qué ocurriría en el siguiente código? for (x = 1; x <= 20; x++); cout << x << endl; A veces sí se usan bucles for con sentencias vacías: todo se hace dentro del for . Ejemplo. MCD de dos enteros a y b. if (b
2.3.2.5. EL BUCLE for COMO CICLO CONTROLADO POR CONDICIÓN Si bien en muchos lenguajes tales como PASCAL, FORTRAN o BASIC el comportamiento del ciclo for es semejante al descrito en la sección anterior, existen otros lenguajes (como es el caso de C y C++) donde este tipo de ciclo no es un ciclo controlado por contador, sino que es un ciclo controlado por condición. Programación I
60
UCENM
En el caso concreto de C++, su sintaxis es la siguiente:
donde,
es la sentencia de inicialización de la variable controladora , es cualquier expresión lógica que verifica si el ciclo debe terminar o no, actualiza el valor de la variable controladora después de cada ejecución de .
Por tanto, la condición impuesta en el ciclo no tiene por que ser de la forma v_c < Vfinal, sino que puede ser cualquier tipo de condición. Esto implica que se puede construir con una sentencia for un ciclo donde no se conoce a priori el número de iteraciones que debe realizar el cuerpo del ciclo. Ejemplo: Construir un programa que indique el número 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 using namespace std; int main(){ int i, valor; Programación I
61
UCENM
cin >> valor; i=0; // inicializacion while (valor !=0){ // condicion cin >> valor; i++; // incremento } cout << "El número de valores introducidos es " << i; } Ejemplo // Programa para contar el número de valores que se // introducen hasta que se encuentra un cero. // --- Usando un ciclo for --#include using namespace std; int main(){ int i, valor; cin >> valor; for (i=0; valor!=0; i++) cin >> valor; cout << "El número de valores introducidos es " << i << endl; } REFLEXIÓN : ¿Cuando usar un ciclo for como ciclo controlado por condición? Cuando el flujo de control del ciclo sea semejante al de un ciclo controlado por contador Se preserve la norma de buena práctica de programación de los ciclos for , es decir, sin modificar en el cuerpo del ciclo la variable controladora Resulte más legible que hacerlo con otro tipo de ciclo .
Ejemplo. Escribe los enteros entre inf y sup, hasta llegar al primer múltiplo de 13. Programación I
62
UCENM
cin >> inf; cin >> sup; for (entero = inf; (entero #include using namespace std; int main(){ int valor, divisor; bool es_primo; cout << "Introduzca un numero natural: "; cin >> valor; es_primo = true; for (divisor = 2 ; divisor < valor ; divisor++) if (valor % divisor == 0) es_primo = false; if (es_primo) cout << valor << " es primo\n"; else cout << valor << " no es primo\n"; } Para hacerlo más eficiente, nos salimos en cuanto sepamos que no es primo. es_primo = true; for (divisor = 2 ; divisor < valor ; divisor++) if (valor % divisor == 0){ Programación I
63
UCENM
es_primo = false; divisor = valor;
// :-((
} Nos salimos del bucle con un bool. La misma variable es_primo nos sirve:
for (divisor = 2 ; divisor < valor && es_primo ; divisor++) if (valor % divisor == 0) es_primo = false; 2.3.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 límite de anidamiento, y la única restricción que se debe satisfacer es que deben estar completamente inscritos unos dentro de otros.
Programación I
64
UCENM
Ejemplo: // Programa que imprime la tabla de multiplicar de // los N primeros números. #include using namespace std; int main(){ const int N=3; int i, j; for (i=1 ; i<=N ; i++) { for (j=1 ; j<=N ; j++) cout << i << "*" << j <<"=" << i*j << " "; cout << endl; } } Salida
¿Qué salida producen los siguientes trozos de código ?
iteraciones=0;
for (i=0; i<3; i++) for (j=0; j<3 ; j++) iteraciones++;
Programación I
65
UCENM
total = 3; for (i=2 ; i<=10 ; i=i+2) for (j=1 ; j<=8 ; j++) total++; cout << total << endl; Ejemplo. Imprimir en pantalla los divisores primos del entero N Algoritmo: Entradas : N Salidas: ninguna Descripción: Recorrer todos los enteros menores que N Comprobar si el entero es primo. En dicho caso, comprobar si divide a N Ineficiente. 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 aún si empezamos desde N/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); for ( divisor_primo = 2 ; divisor_primo <= tope && es_primo ; divisor_primo++){ if (divisor_N % divisor_primo == 0) es_primo = false; } if (es_primo)
Programación I
66
UCENM
cout << "\nEl primo " << divisor_N << " divide a " << N; } }
Programación I
67
UCENM
Ejercicios propuestos 1. Determinar cuales de los siguientes son identicadores validos. Si son invalidos explicar por que. a) registro1 b) 1registro c) archivo_3 d) main e) nombre y direccion f) direccion g) diseño 2. Determinar cuales de las siguientes son constantes de cadena de caracteres validas, 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."' d) "Direccion\n" e) "Direccion'n" f) "Direccion\'n" g) "Direccion\\'n" 3. Reescribir las siguientes expresiones con parentesis, teniendo en cuenta la precedencia de los operadores. a) a+b*c-d
b) a * b / c
c) a * c % b - d
4. Realizar un programa para intercambiar los contenidos de dos variables enteras. 5. Realizar un programa que declare las variables x, y y z, les asigne los valores 10, 20 y 30 e intercambien entre si sus valores de forma que el valor de x pasa a y, el de y pasa a z y el valor de z pasa a x (se pueden declarar tantas variables adicionales como se desee). 6. Razonar sobre la falsedad o no de las siguientes afirmaciones: a) 'c' es una expresión de caracteres. b) (4+3)<5 es una expresión numérica. c) 4<3 es una expresión numérica. d) cout <Que realiza cin >>cte, siendo cte una constante entera? 7. Diseñar un programa que lea un carácter en mayúscula, lo pase a minúscula y lo imprima en pantalla. 8. Dado un carácter que contiene un valor entre '0' y '9' extraer su valor numérico. Por ejemplo, para '7' queremos obtener el entero 7. 9. Escribir una expresión lógica que sea verdadera si el carácter letra es una letra minúscula y falso en otro caso. Programación I
68
UCENM
10. Encontrar el valor de la variable Final después de la ejecución de este código real1 = 4.0; real2 = 3.0; resultado = real1/real2 - real1*real2; cout << "\nResultado = " << resultado; dependiendo de si las variables reales se declaran como float o como double. 11. Indique que tipo de dato usara para representar: Edad de una persona Producto interior bruto de un país Ingresos anuales Sexo de una persona Estado civil 12.. El precio final de un automóvil para un comprador es la suma total del costo del vehiculo, del porcentaje de ganancia de dicho vendedor y del IMP. Diseñar un algoritmo para obtener el precio final de un automóvil sabiendo que el porcentaje de ganancia de este vendedor es del 20% y el IMP. Aplicable es del 12 %. Ejercicios de estructura de control repetitivo 1.- Realizar un programa que lea desde teclado un entero final e imprima en pantalla todos sus divisores. Obligad a que el entero leído sea un positivo. Para obtener los divisores, basta recorrer todos los enteros menores que el valor introducido y comprobar si lo dividen. 2.- Realizar un programa que lea números reales desde teclado y calcule el Máximo de dichos valores. Se dejara de leer datos cuando el usuario introduzca un valor negativo. Realizad la lectura de los reales dentro de un bucle sobre una única variable llamada dato. 3,- Un banco presenta la siguiente oferta. Si se deposita una cantidad de lempiras C (de Capital) durante un año a plazo fijo, se dará un interés del I %. Realizad un programa que lea una cantidad C y un
Programación I
69
UCENM
interés I desde teclado y calcule e imprima el dinero que se tendrá al cabo de un año. Tanto el capital como el interés serán valores reales. Además el interés se introducirá como un valor entre 0 y 1, es decir, un interés del 5% se introducirá como 0.05 4.- Supongamos ahora que se quiere reinvertir todo el dinero obtenido (el original C mas los intereses producidos) en otro plazo fijo a un año. Haga un programa para que lea un numero de años N, y calcule e imprima todo el dinero obtenido durante cada uno de los N años, suponiendo que todo lo ganado (incluido el capital original C ) se reinvierte a plazo fijo durante el siguiente ano. El programa debe mostrar una salida del tipo: Capital en el año numero 1 = 240 Capital en el año numero 2 = 288 Capital en el año numero 3 = 345.6
Programación I
70
UCENM
Guia proctica capitulo 1 1. introducción
Esta guía practica esta orientada para que el alumno de educación a distancia pueda realizarlos en el tiempo que no este con su tutor, de forma autónoma, no necesitando mas que la información que se proporciona en ellos, junto con los conocimientos previamente adquiridos tanto en las clases de teoría como de practicas, que se llevaran a cabo con el docente encargado de la materia. Su estructura es de la siguiente forma: Sección se describe la habilidad que el alumno debe adquirir. Dentro de cada sección se presenta un ejemplo practico que ilustra las tareas necesarias que se necesitan para el aprendizaje de la habilidad. Después de dicho ejemplo, aparece uno o más ejercicios para consolidar la habilidad. Estos ejercicios pueden ser de los siguientes o Ejercicios obligatorios: Los alumnos deben realizarlos en la sesión de practicas justo en el momento en el que aparecen en la descripción de la sección o Ejercicios optativos: Son ejercicios pensados para aquellos alumnos que, habiendo terminado los ejercicios obligatorios, dispusieran de tiempo restante para seguir haciendo ejercicios. La resolucion de dichos ejercicios puede retrasarse hasta que se complete el guion. Aunque su resolucion no es obligatoria, si que resulta conveniente intentar realizarla en la correspondiente sesion de practicas. o . Ejercicios adicionales: Son ejercicios adicionales para reforzar la habilidad adquirida. No es necesario que se realicen durante la sesion de practicas.
Introducción a Dev-C++ Para la realización de estas practicas de la asignatura programación I, se utilizara el entorno de programación Dev-C++.
Programación I
71
UCENM
Dev-C++ es un Entorno de Desarrollo Integrado (IDE) para el lenguaje de Programación C/C++ que usa Mingw de GCC (GNU Compiler Collection) como compilador y permite crear: o Programas ejecutables para Win32. o Programas ejecutables para consola. o Construcción de DLLs y bibliotecas estáticas. o Además, se puede utilizar en combinacion con otros compiladores basados en GCC.
Dev-C++ es un software de libre distribucion ( www.bloodshed.net ) sujeto a los términos de la Licencia Publica General (GPL) de GNU. Vamos a utilizar la versión 5 Beta 9 (4.9.9.2) y sus características mas relevantes son : o Soporta compiladores basados en GCC, como por ejemplo el Mingw. o Tiene integrado un depurador basado en GDB. o Soporta multiples lenguajes (el castellano es uno de ellos). Programación I
72
UCENM
Mantiene una lista con las clases utilizadas en el desarrollo de un programa. o Tiene ayuda para el autocompletado del código. o Mantiene la lista de funciones definidas en el desarrollo del programa. Tiene un manejador de proyectos (se usa cuando el programa se o compone de mas de un fichero fuente). o Tiene un editor que resalta la sintaxis del código que es configurable. Soporta plantillas para la creación de tus propios tipos de proyectos. o Crea Makefiles para la compilación separada de archivos fuente. o o Edita y compila ficheros de recursos. Soporta la actualización del software y bibliotecas a traves de Internet. o Instalación de Dev-C++ Requisitos del sistema Los requerimientos mínimos para ejecutar Dev-C++ son: Microsoft Windows 95, 98, NT 4, 2000, XP 32 MB RAM 100 Mhz Intel compatible CPU 30 MB de espacio libre de disco Los requerimientos aconsejados para Dev-C++ son: Microsoft Windows 2000, XP 64 MB RAM 400 Mhz Intel compatible CPU 200 MB de espacio libre de disco o
En la pagina www.bloodshed.net/dev/devcpp.html se puede encontrar la ultima versión del entorno de programación. Una vez conseguido, el fichero de instalación devcpp-4.9.9.2 setup.exe contiene todo lo necesario para instalar el entorno de programacion Dev-C++ y el compilador de C/C++.
Programación I
73
UCENM
Ejecutar el programa de instalación La instalación de este software es bastante simple. Únicamente hay que acceder al directorio donde se descargo y hacer doble click sobre el fichero devcpp-4.9.9.2 setup.exe. Automáticamente, se ejecuta el software de instalación, será necesario seguir los siguientes pasos. 1. Seleccionamos el idioma en el que se instalara el programa (Figura 2). 2. Aceptamos la licencia para lo cual pinch amos en ”Acepto” (Figura3). 3. Tomamos la instalacion tipica ”Full” seleccinando ”Siguiente” (Figura 4) 4. Elegimos el directorio donde se desea instalar. Se puede dejar el que viene por defecto seleccionado en ”Instalar” (Figura 5). El software de instalación copiara los archivos en el directorio elegido y para terminar la instalación seleccionamos ”Terminar” (Figura 6). 5. Arrancar el entorno por primera vez. Una vez arrancado el entorno por primera vez (Figura 7).
Programación I
74
UCENM
Programación I
75
UCENM
Algunas configuraciones posteriores. a) Poner el idioma en Españo. Una de las ventajas de este software es que permite personalizar el entorno de programación al idioma español. Para poner esta configuracion s e elige la opcion ”Tools”” Environment Options”. Tras dicha eleccion aparece la ventana de la Figura (8), donde en el apartado ”Language” debemos elegir la opcion ”Español(Castellano)” y pulsar el boton ”Ok”.Esta operacion pondra todos los menus y opciones del entorno en el idioma Español. b) Mantener actualizado el entorno. En el caso de disponer en casa de conexión a Internet se puede actualizar el entorno, ya que este software aun esta en fase de desarrollo y con bastante Frecuencia aparecen nuevas modificaciones. Para actualizar el entorno, elegimos la opcion ”Herramientas” ”Buscar actualizaciones”. c ) Habilitar depuración de programas. ”Herramientas” ”Opciones de Compilador” (Figura 9), poner a ”Yes” la opcion ”Generar informacion de debug”.
Programación I
76
UCENM
Programación I
77
UCENM
d ) Activar las copias de seguridad de los ficheros de programas. ”Herramientas” ”Opciones de Entorno” ”Principal” ”Crear archivo de respaldo” (Figura 10). e) ”Herramientas” ”Opciones del editor” ”Principal” ”Resaltar llaves y parentesis concordantes” Permite ver
resaltadas y emparejadas las llaves y los par´entesis (Figura 11. f ) ”Herramientas”-”Opciones del editor”-”Visualizacion”-”numero de linea” para ver las lıneas de codigo numeradas en una secuencia que aparece a la izquierda de la ventana de texto (Figura 12. g ) Para mostrar la sintaxis resaltada (coloreada) y poder detectar algunos errores sintacticos de forma rapida. ”Herramientas” ”Opciones del editor”-”Sintaxis” -”Preconfiguraciones” -”Classic”
(Figura 13).
Programación I
78
UCENM
Programación I
79
UCENM
Creación del primer programa Edicion Para crear un programa nuevo seleccionamos”Archivo” ”Nuevo” ”Codigo Fuente” (Figura 14) Y a continuación, escribimos en la
ventana de texto el programa a implementar (figura 15)
Programación I
80
UCENM
Compilacion Despues de escribir y guardar el codigo fuente del programa pasamos a generar un fichero en codigo maquina que permita ejecutar en el computador el algoritmo que hemos construido (”Ejecutar” -”Compilar” o bien el metodo abreviado ”Ctrl+F9”, o bien pulsando sobre el icono ). La compilación tiene asociado tres procesos que se ejecutan de forma secuencial: 1. Se aplican sobre el fichero fuente las modificaciones que indican las directivas de precompilacion indicadas en código fuente inicial. 2. Ese código fuente modificada se traduce a un lenguaje Intermedio conocido como código objeto. Este código objeto es Prácticamente el código maquina de nuestro código fuente a falta de incluir el código maquina de las funciones que se han Utilizado. Para que el proceso de compilación se realice de forma correcta y se obtenga el código objeto, es necesario que el codigo fuente no contenga errores sintácticos. Si aparecen errores, es necesario volver a la fase de edición, guardar de nuevo el código fuente y repetir la fase de compilación. 3. A partir del código objeto, se genera un fichero ejecutable mediante el proceso de enlazado. Esta ultima fase, completa el código objeto añadiendo los trozos de código maquina que quedan pendientes de resolver. El fichero ejecutable tiene el mismo nombre que el nombre del fichero fuente, pero cambiando su extensión por .exe. Como resultado de la fase de compilación, en la pestaña Resultado de la compilación debe aparecer algo como lo que muestra la Figura16 Esto indica que hemos conseguido generar un fichero ejecutable que se llamara igual que nuestro fichero pero sustituyendo la extensión ”cpp” por ”exe”.
Programación I
81
UCENM
Figura 16 programa con errores y sin errores
Prueba del programa Uno podría pensar que una vez que consigo un fichero ejecutable a partir de mi código fuente, el problema esta terminado. Sin embargo esto no es así. Tras el proceso de compilado se requiere una fase de prueba. Dicha fase intenta probar que el algoritmo planteado resuelve el problema propuesto. Para llevar a cabo esta fase, es necesario ejecutar el programa y verificar que los resultados que obtiene son los esperados. Para ejecutar un programa que hemos compilado basta con pulsar el icono o con el método abreviado ”Ctrl+F10” o bien con la opción de menú “Ejecutar”+”Ejecutar”.
La ejecución del programa se realizara en una ventana de MS-DOS Emergente como la mostrada en la Figura 17
La
Programación I
82
UCENM
ejecución del programa se detendrá en aquellos puntos del mismo donde se requiera la interacción del usuario para poder proseguir, es decir, en las operaciones de entrada de datos a través del dispositivo estándar de entrada. Una vez que el algoritmo supera la fase de prueba, podemos considerar que se ha concluido con la fase inicial del desarrollo del software, pero ¿donde se encuentra el fichero ejecutable? Por defecto, el fichero ejecutable se crea en el mismo directorio donde se almaceno el fichero fuente. Para mostrar que el fichero generado es independiente del entorno de programación, hacemos lo siguiente: Introducción a la corrección de errores Si ya instalo su compilador devxxxx, introduzca el código siguiente /* Calculo los divisores de un número entero positivo >0 */ #include using namespace std; int main(){ int numero, divisor // Entrada de datos do{ cout << "Introduce un numero entero positivo mayor que 0: "; cin >> numero; }while (numero<=0); // Fase de cálculo for (divisor=1; divisor<=numero; divisor++) if (numero%divisor==0) cout << divisor << " es un divisor de " << numero << endl; /* para deter la ejecución */ cout << "Pulsa una tecla y RETURN para continuar\n"; cin >> divisor; } Programación I
83
UCENM
1.- Que contiene el código fuente necesario para calcular los divisores de un numero entero positivo mayor que 0. 2. Ejecutar el entorno de DevC++ . 3. Compilar el código fuente (“Ctrl+F9”).
Podemos observar que la compilación no se ha realizado con Éxito tal y como muestra la Figura 19. Cuando esto sucede en la parte inferior de la ventana principal aparece activada la pestaña “Compilador”. En ella aparece una tabla con tres columnas: línea, unidad, mensaje. La primera de ellas indica la línea donde el compilador detecto el error sobre el archivo fuente. Este dato se debe interpretar como que el error se encuentra en esta línea o en alguna de las líneas anteriores a esta. Archivo o Unidad indica la ubicación del archivo en la unidad de almacenamiento. El mensaje indica el tipo de error detectado por el compilador. Normalmente, aparece una fila dentro de esta ventana que no tiene asociado numero de línea. Esta fila da información sobre la función en la que se produjo el error. En el caso anterior, podemos leer: In function ’int main()’:
que debemos interpretar como que el error o errores que se detallan a continuación están localizados en el programa principal. Los pasos que debemos seguir para la corrección son los siguientes:
Programación I
84
UCENM
1. Ir a la primera fila de la ventana que tiene asociado un numero De línea. 2. Leer el mensaje de error e intentar entenderlo. 3. Hacer doble click sobre esa fila con el ratón. Esto nos posiciona sobre la línea en el fichero fuente donde el compilador detecto el error. 4. Comprobar la sintaxis de la sentencia que aparece en esa línea. Si se detecta el error, corregirlo. Si no se detecta el error mirar en La línea anterior, comprobar la sintaxis y repetir el proceso hasta Encontrar el error. 5. Después de corregir el posible error, guardamos de nuevo el Archivo y volvemos a compilar. Esto lo hacemos aunque Aparezcan más errores en la ventana. La razón es que es Posible que el resto de los errores sean consecuencia del primer error. 6. Si después de corregir el error aparecen nuevos errores, volver a Repetir el proceso desde el paso 1.
Programación I
85
UCENM
7. Ahora, aplicaremos este proceso a nuestro ejemplo, así que nos vamos a la primera fila que contiene numero de línea (Figura 20 ) El error que nos aparece suele ser el mas común, es un error sintáctico y se debe a que el compilador se ha encontrado con un token (la palabrareservada ’do’ en este caso) que no es el tipo de
token que esperaba. Este tipo de errores los debemos interpretar como que nos hemos equivocado en la sintaxis de una sentencia anterior a donde dice que esta el error. Hacemos doble click sobre esta fila, y el cursor se posiciona sobre la línea indicada en el editor. En nuestro caso, se sitúa sobre la sentencia que aparece remarcada en rojo en la Figura 19 en la que no parece haber ningún error. Así que miramos la línea anterior. En ella encontramos un comentario que podemos observar que esta bien construido; por consiguiente, el error tampoco se encuentra en esta línea. En la línea anterior al comentario hay una línea vacía. Aquí tampoco esta el error, así que tenemos que seguir con la anterior. En dicha línea nos encontramos la siguiente sentencia: int numero, divisor Es una sentencia de declaración de variables en la que podemos observar que no esta correcta, ya que le falta el punto y coma que indica el final de la sentencia. Una vez detectado el error, lo corregimos añadiendo el punto y coma que falta, guardamos el fichero y volvemos a compilar. Podemos observar que la nueva compilación es exitosa y no se ha encontrado ningún error. Ejecutamos el programa y probamos que funciona correctamente.
/*
Programación I
86
UCENM
Este programa calcula la descomposición en número primos de un numero positivo mayor que 0*/ #include #include using namespace std; int main(){ int numero, i, elevado=0; // Entrada de datos do{ cout << "Introduce un numero entero mayor que 0: "; cin >> numero; }while (numero<=0); i=2; while (numero>1){ if (numero%i==0){ numero = numero/i; elevado++; } else { if (elevado!=0) cout << i << " elevado a " << elevado << endl; elevado=0; i++; } } cout << i << " elevado a " << elevado << endl; // detener la ejecución cout << "Pulsa una tecla para acabar\n"; getch(); } Programación I
87
UCENM
Para familiarizarnos con los errores mas frecuentes y su corrección Vamos a realizar el siguiente proceso: a partir de un código fuente que compila perfectamente iremos introduciendo deliberadamente errores para conocer que mensajes nos aparecen. Digite el programa que calcula la descomposición descomposición en números primos
1.- Introducir el error que se indica en la lista que aparece mas adelante. 2. Guardamos el fichero. 3. Compilamos el código modificado con la introducción del error. 4. Miramos el error y lo anotamos en la tabla . 5. Corregir el error y pasar a introducir el siguiente error de la lista. La lista de errores que introduciremos son los siguientes: 1. Falta el fichero de cabecera de alguna biblioteca donde se encuentra definida alguna función utilizada en el programa. Acción: Convertimos en un comentario la primera línea del programa añadiendo dos barras invertidas antes de la sentencia, es decir, dejándola como: // #include 2. El mismo error anterior, pero esta vez comentando el fichero de cabecera iostream. Accion: Convertimos en comentario: // #include 3. Nos equivocamos al introducir el nombre del fichero de cabecera. iostream, el nombre iotream. iotream. Accion: Poner en lugar de iostream, 4. Se nos olvida los paréntesis de la función principal. Acción: Borrar los dos paréntesis de la declaración de la función main, de manera que quede de la siguiente forma: int main { 5. Introducimos un identificador incorrecto. Acción: En la definición de variables cambiar el nombre a la variable número por número por el identificador identificador 1numero 1numero.. Programación I
88
UCENM
6. Se nos olvida una de las dobles comillas en una constante de cadena de caracteres. Acción: Quitar las dobles comillas finales de la sentencia: cout << "Introduce un numero mayor que 0; 7. Se nos olvida cerrar alguna de las llaves que definen el cuerpo de Un ciclo o una estructura condicional. else. Acción: Borrar la llave que se encuentra antes del else. 8. Usar una variable no declarada. identificador numero numero.. Acción: Borrar en la declaración de variables el identificador 9. Cambiamos de sentido las dobles puntas de flecha en un cout cout, Acción: Cambiamos las dobles puntas de flecha del primer cout, es decir, cout >> "Introduce un numero entero mayor que 0: "; Ahora proponemos proponemos algunos algunos ejercicios para afianzar los conocimientos Ejercicio numero 1 Copie o corrija el siguiente programa o algoritmo. Guardelo en su directorio personal. #include using namespace std; int main{ char l; int ca=0, ce=0, ci=0, co=0, cu=0, cd=0, 1n, i do{ cout << "Introduce el numero de caracteres que se van a leer: "; cin >> n; }while (n<=0) for (i=0; i>l; switch(l) { Programación I
89
UCENM
case 'a': case 'A': ca++; break; case 'e': case 'E': ce++; break; case 'i': case 'I': ci++; break; case 'o': case 'O': co++; break; case 'u': case 'U': cu++; break; default: cd++; break; } } cout <
Programación I
90
UCENM
Depuración. Un depurador de programas ( debugger en ingles) permite ir ejecutando un programa sentencia a sentencia (ejecucion paso a paso). Además, nos permite ver en cualquier momento el valor de las variables usadas por el programa. El uso de un depurador facilita la localización de errores lógicos en nuestros programas, que de otra forma resultaran bastante difíciles de localizar directamente en el código. Esta sección esta dedicada a aprender el funcionamiento de un depurador de programas. En particular, usaremos el depurador gdb que esta integrado en el entorno Dev-C++. Para aprender las principales utilidades que tiene el depurador de programas del Dev-C++, vamos a depurar una versión del programa polinomio.cpp Una vez abierto el fichero con el Dev-C++, lo compilaremos. Antes de compilar, debemos asegurarnos que esta seleccionada la opción Generar Información de Debug en el Dev-C++ (Menu Herramientas” ”Opciones del Compilador” -”Linker”, ver Figura 9), para que así se añada al fichero ejecutable, cierta información que luego necesita usar el depurador de programas. Ejecuta el programa polinomio.cpp, probando todas las opciones, y con diferentes números. Comprueba que el programa da resultados correctos. /* Programa para la gestión de polinomios de segundo grado */ #include #include using namespace std; int main() { double a, b, c, x1, x2, rad; char opcion; int i; bool haypol=false, terminar=false; do { Programación I
91
UCENM
/* Menu principal */ do { // ciclo para pintar una línea de asteriscos for (i=1; i<56;i++) cout << "*"; cout << endl; cout << "* Menú Principal // ciclo para pintar una línea de asteriscos for (i=1; i<56;i++) cout << "*"; cout << endl;
*\n";
// Opciones del programa if haypol cout << "El polinomion existente es: " << a << "x2+" << b << "x+" << c << endl; else cout << "Aún no se ha introducido ningún polinomio" << endl; cout << "Introduce la opción deseada:" << endl; cout <<"\t 1. Leer Coeficientes\n"; cout <<"\t 2. Encontrar raices\n"; cout <<"\t 3. Salir\n"; cout <<"\n\t\t Elige opcion: "; cin >> opcion; }while (opcion<'1' || opcion>'3'); switch(opcion) { case '1': cout << "Introduce el coeficiente \"a\": "; cin >> a; cout << "Introduce el coeficiente \"b\": "; cin >> b; cout << "Introduce el coeficiente \"c\": "; cin << c; haypol=true; break; case '2': if (haypol) { rad=pow(b,2)-4*a*c; if (rad >= 0) { Programación I
92
UCENM
x1=(-b+sqrt(pow(b,2)-4*a*c))/(2*a); x2=(-b-sqrt(pow(b,2)-4*a*c))/(2*a); cout << " Primera Raiz: " << x1 << endl; cout << " Segunda Raiz: " << x2 << endl; else cerr << "Raíces complejas. No es posible hacer el cálculo" << endl; } else cerr << "Aún no se ha introducido ningún polinomio" << endl; break; case '3': terminar=true; break; } }while (terminar==false); // Esta condición se podría poner también como while (!terminar) } Para comenzar la depuración colocaremos el cursor sobre la sentencia de la línea 29 if (haypol) y pulsaremos “Ctrl+F5”. Veremos que la instrucción queda marcada en rojo y pulsamos la Pestaña inferior de depuración ( ) para abrir la ventana de controles del depurador (Figura 21). Lo que hemos hecho es pedirle al depurador que detenga la ejecucion del programa en este punto (esto se conoce como un punto de ruptura o breakpoint
Programación I
93
UCENM
A continuación le pediremos al depurador que empiece a ejecutar nuestro programa pulsando sobre el botón . Esto provocara que el programa empiece a ejecutarse, mostrando la lınea que se va a ejecutar a continuación remarcada en azul (Figura 22) mostrando la ventana de ejecución del programa (Figura 23).
Control de la depuración A partir de ahora podremos realizar una serie de acciones mediante las cuales podremos examinar el contenido de variables, ejecutar el programa paso a paso o bien dejar que continúen la ejecución hasta el final. Los botones asociados a estas acciones para el control de la ejecución del depurador son las siguientes: “Siguiente Paso”: Ejecuta la siguiente instrucción del
programa (aquella que aparece resaltada en color azul). También podríamos haberlo hecho con el botó n “Avanzar Paso a paso”
“Saltar Paso”: Ejecuta instrucciones hasta el siguiente
punto de ruptura o hasta el final del programa en caso de que no haya ninguno mas. “Ir a cursor”: Ejecuta sentencias hasta el lug ar donde se
sitúa el cursor. Se puede aplicar al comenzar la depuración para saltar determinadas sentencias que no queremos revisar. Al usarlo tras el comienzo de la depuración, simplemente introduce un punto de ruptura, tal y como hemos hecho anterioremente. Después podríamos avanzar usando “Saltar Paso” para alcanzar este punto, el cual dejar a de ser punto de ruptura.
Programación I
94
UCENM
“Parar ejecución”: Cuando deseemos terminar el programa en el punto
actual, sin llegar al final del programa podemos escoger esta opción
Figura 23: El programa se esta ejecutando en esta ventana, pero se encuentra interrumpido, a punto de ejecutar la sentencia que aparece remarcada en azul (Figura 22) Programación I
95
UCENM