Introducción a los Computadores Práctica nº 2 Introducción. Un programa en C++ tendrá para nosotros el siguiente esquema básico: /*-----------------------------------------------------------------| Autor: | | Fecha: Versión: 1.0 | |-------------------------------------------------------------------| | Descripción del Programa: | | | | ------------------------------------------------------------------*/ // Incluir E/S y Librerías Standard #include <iostream> #include <cstdlib> using namespace std; // Zona de Declaración de Constantes // Zona de Declaración de Tipos // Zona de Cabeceras de Procedimientos y Funciones // Programa Principal int main() { // Zona de Declaración de Variables del Programa principal // Zona de instrucciones system("Pause"); return 0; // Hacer una pausa // Valor de retorno al S.O. } // Implementación de Procedimientos y Funciones Toda sentencia en C++ que no sea un comentario, un bloque ‘{ }’ o una directiva del preprocesador termina con “punto y coma” (';') Tipos simples predefinidos. En C++ se encuentran predefinidos los tipos básicos especificados en la siguiente tabla: Pseudolenguaje N Z Tipo C++ Valores unsigned int unsigned short int unsigned long int int short int long int 0 a 4.294.967.295 0 a 65.535 0 a 4.294.967.295 -2.147.483.648 a +2.147.483.647 -32.768 a +32.767 -2.147.483.648 a +2.147.483.647 Pág 1 Introducción a los Computadores Pseudolenguaje Tipo C++ float R double long double C char B bool void Práctica 2 Valores Epsilon de float: 1,19209290 e-07 Mínimo de float: 1,17549435 e-45 Máximo de float: 3,40282347 e+38 Epsilon de double 1,1102230246251568 e-16 Mínimo de double 2,2250738585072014 e-323 Máximo de double 1,7976931348623157 e+308 Epsilon de long double 1,1102230246251568 e-16 Mínimo de long double 2,2250738585072014 e-323 Máximo de long double 1,7976931348623157 e+308 Código ASCII true false Tipo vacío (usado para subprogramas) Para el tipo NATURAL (N) usaremos siempre unsigned int, para el tipo ENTERO (Z) usaremos siempre int, y para el tipo REAL (R) usaremos siempre float. Declaración de Variables. Las variables en C++ se declaran en la zona indicada en el fragmento de código del principio y no van precedidas por ninguna palabra reservada que indique dicha sección. Las variables de declaran separadas por comas y precedidas del nombre del tipo. Formalmente: <tipo> <identificador> { , <identificador> } [= <valor>]; Donde: <identificador> ::= <carácter_ident> { <carácter_ident> | <dígito> } <carácter_ident> ::= a | b |···| z | A | B |··· | Z | _ <dígito> ::= 0 | 1 | 2 | ··· | 9 Ejemplos: int num_1; int num_2 = -28; // Equivale a: int num_2; num_2 = 28; Nota: En los identificadores de variables usaremos siempre letras minúsculas. Declaración de Constantes. Al igual que las variables, las constantes en C++ se declaran en la zona indicada en el fragmento de código del principio y no van precedidas por ninguna palabra reservada que indique dicha sección. Las constantes en C++ se declaran igual que las variables pero precedidas por la palabra reservada const y con una asignación del valor. Formalmente: const <tipo> <identificador> = <valor> ; Donde: <valor> ::= <num_natural> | <num_entero> | <num_real> | <car> <num_natural> ::= <dígito> {<dígito>} <num_entero> ::= [+|-] <num_natural> <num_real> ::= <num_entero>.{<dígito>} [(e|E) <num_entero>] <car> ::= ' <carácter> ' Como valores constantes de carácter también se pueden usar determinados caracteres de control expresados mediante las siguientes secuencias de escape: '\0' '\a' carácter nulo campana sonora '\n' '\t' salto de línea tabulador Pág. 2 Introducción a los Computadores retroceso salto de página (borrado de pantalla) comilla simple '\b' '\f' '\'' Ejemplos: Práctica 2 '\r' '\\' '\"' retorno de carro barra invertida comilla doble const float PI = 3.1415929; const char FINLINEA = '\n'; Nota: En los identificadores de constantes usaremos siempre letras mayúsculas. Operadores básicos. En la siguiente tabla se presentan los operadores básicos para los tipos de datos simples predefinidos. Pseudolenguaje C++ Significado Aplicable a = == != > < >= <= x = x + 1 x = x – 1 + * DIV / MOD = == != > < >= <= ++ -+ * / / % +=, -=, *=, /=, %= +=, -=, *=, /= abs(x) Asignación Igualdad Desigualdad Mayor que Menor que Mayor o igual que Menor o igual que Incremento Decremento Suma Resta, cambio de signo Producto División entera (cociente) División real (cociente) Modulo entero (resto) char, unsigned int, int, float, bool char, unsigned int, int, float, bool char, unsigned int, int, float, bool char, unsigned int, int, float char, unsigned int, int, float char, unsigned int, int, float char, unsigned int, int, float char, unsigned int, int char, unsigned int, int unsigned int, int, float unsigned int, int, float unsigned int, int, float unsigned int, int float unsigned int, int Acumuladores y contadores unsigned int, int Acumuladores y contadores float Valor absoluto de x Iniciar generador de números aleatorios (x: semilla) Obtiene numero aleatorio Valor absoluto de x x elevado a la potencia y Raíz cuadrada de x Seno de x (en radianes) Coseno de x (en radianes) Tangente de x (en radianes) Arco seno de x (en radianes) Arco coseno de x (en radianes) Arco tangente de x (en radianes) e elevado a x Logaritmo neperiano de x Logaritmo en base 10 de x Entero superior a x Entero inferior a x Y lógico O lógico NO lógico int x = x <op> E x = x <op> E ABS (x) srand(x) ABS (x) POW (x, y) SQRT (x) Y O NO rand() fabs(x) pow(x,y) sqrt(x) sin(x) cos(x) tan(x) asin(x) acos(x) atan(x) exp(x) log(x) log10(x) ceil(x) floor(x) && || ! int int float float float float float float float float float float float float float float bool bool bool Se necesita incluir: #include <cmath> ¡CUIDADO! El operador de igualdad está compuesto por DOS signos igual (==) y la asignación por UN solo signo igual (=). Pág. 3 Introducción a los Computadores Práctica 2 NOTA IMPORTANTE: Una asignación es una expresión válida en C++. if ( x = 3 ) // Es sintácticamente correcto y siempre valdrá true Expresiones. Precedencia y asociatividad Resumen de operadores, su precedencia (de mayor a menor) y asociatividad: Precedencia Operadores 1 2 3 4 5 6 7 8 9 10 11 Incremento sufijo Decremento sufijo Llamada a función, casting Elemento de array Acceso a miembros Incremento prefijo Decremento prefijo Negación lógica Cambio de signo Signo positivo Tamaño en bytes Multiplicación División Resto de división entera Suma Resta Flujo de salida Flujo de entrada Menor que Menor o igual que Mayor que Mayor o igual que Igual Desigual Conjunción lógica Disyunción lógica Asignación simple Asignaciones compuestas Separador de expresiones Símbolos Asociatividad ++ -() [] . , -> ++ -! + sizeof() * / % + << >> < <= > >= == != && || = += , -= , *= , /= , %= , Dcha - izda Dcha - izda Dcha - izda Dcha - izda Dcha - izda Dcha - izda Dcha - izda Dcha - izda Dcha - izda Dcha - izda Dcha - izda Izda - dcha Izda - dcha Izda - dcha Izda - dcha Izda - dcha Izda - dcha Izda - dcha Izda - dcha Izda - dcha Izda - dcha Izda - dcha Izda - dcha Izda - dcha Izda - dcha Izda - dcha Dcha - izda Dcha - izda Izda - dcha Expresiones. Conversiones de tipo. C++ es un lenguaje tipado. Ello significa que el compilador chequea los tipos de los valores que aparecen en las sentencias y expresiones para asegurar la compatibilidad de los mismos. Conversión implícita. En C++ todos los tipos de datos que representan números se consideran compatibles, pudiendo por tanto intercambiarse valores entre los distintos tipos. El rango o categoría de mayor a menor de dichos tipos es: long double, double, float, unsigned long, long, unsigned int, int, short int. Promoción de tipos. En cualquier operación en la que aparezcan dos tipos diferentes, se "promociona" el valor del operando de menor categoría al tipo del de mayor categoría. Así, por ejemplo, las variables y constantes float se convierten a double. Sentencia de asignación. En la sentencia de asignación, el resultado final (la expresión a la derecha del operador de asignación) se reconvierte al tipo de la variable a la que se esté asignando. Esto implica que Pág. 4 Introducción a los Computadores Práctica 2 puede producirse una promoción, o una pérdida de rango. De todas formas conviene normalmente hacer una conversión explícita "(cast)". Conversión explícita (cast). Sirve para forzar un cambio de tipo en el resultado de una expresión. <tipo> ( <expresion> ) El valor de la expresión se convierte al tipo que la precede. Por ejemplo, para calcular la raíz cuadrada de un entero “n”: sqrt (float (n)) Entrada y Salida Básica en C++. Para usar la entrada y salida básica en C++ es necesario incluir la directiva del preprocesador: #include <iostream>. Y la cláusula “using namespace std;”. Flujo de entrada (Leer). Para Leer datos desde teclado se usa cin, por tanto, se mandan (>>) valores desde cin a la variable: cin >> <variable> ; Se puede encadenar la lectura de varias variables usando múltiples operadores (>>). Por ejemplo: cin >> a >> b; Leería dos valores separados por espacios, tabuladores o cambios de línea sobre las variables a y b. Sin embargo, cin tiene el problema de que ignora los caracteres de control, espacios y tabuladores. Cuando queramos leer un carácter que pueda ser de control se usará cin.get() y si queremos leer una línea entera, usaremos cin.getline(). Flujo de salida (Escribir). Para Escribir datos a pantalla se usa cout, por tanto, se mandan (<<) valores de variable, expresiones o constantes hacia cout. La constante endl denota el fin de línea. cout << <expresion> ; También se puede encadenar la salida del valor de varias variables, expresiones o constantes usando múltiples operadores (<<). Por ejemplo: cout << "El valor es " << a << endl; Presentaría en la pantalla el texto "El valor es " seguido del valor de la variable a y seguidamente efectuaría un salto de línea. Salida con formato. En el flujo de salida cout se pueden insertar unos manipuladores que permiten alterar el formato de presentación del siguiente valor a escribir. Pág. 5 Introducción a los Computadores Práctica 2 Para usar estos manipuladores es necesario incluir la directiva del preprocesador: #include <iomanip> Los manipuladores básicos son: • • • • setprecision(x) Donde x es un número natural que indica el número de dígitos significativos de un dato real (float, double o long double). fixed Sin ningún tipo de parámetros. El manipulador fixed hace que el siguiente manipulador setprecision en el flujo se aplique a los dígitos fraccionarios únicamente. setw(x). Donde x es un número natural que permite indicar el número de espacios que se emplearán para escribir un dato, alineando al mismo a la derecha dentro de dicho espacio. Si el espacio requerido es mayor que el indicado, el manipulador se ignora. setfill(c). Donde c es un carácter que especifica el carácter de relleno que se empleará para los espacios no usados al escribir un dato (según un manipulador setw()). Sentencia nula. Una sentencia nula se indica por medio de un punto y coma: ; Necesaria en algunas ocasiones por la sintaxis. Sentencia bloque o compuesta. Una sentencia compuesta se usa: • Para agrupar un conjunto de sentencias en una única sentencia lógica. • Como cuerpo de una función, como se verá más adelante. • Para limitar la visibilidad o ámbito de ciertas definiciones a una parte del programa (bloques). De hecho las variables definidas dentro de un bloque sólo son visibles dentro del mismo (variables locales). La notación BNF de esta sentencia es la siguiente: <bloque> ::= '{' {<sentencia>} '}' El estilo de codificación que usaremos para los bloques será situar las llaves de apertura y cierre en líneas independientes y las sentencias contenidas en el bloque sangradas a la derecha. { <sentencias> } Ejemplo: { int a, b, c; a = b + c; b ++; cout << b; } Sentencias de selección en C++. Las estructuras de selección o condicionales controlan si una sentencia o secuencia de sentencias se ejecutan, en función del cumplimiento o no de una condición o expresión lógica. C++ tiene dos estructuras de control para la selección, if y switch. Pág. 6 Introducción a los Computadores Práctica 2 Sentencia if La sentencia if elige entre una, dos o más alternativas en base al valor de una o más expresiones lógicas. La notación BNF de esta sentencia es la siguiente: <sent_if> ::= if '('< expres_log> ')' (<sent> | <bloque>) {else if '(' <expres_log> ')' (<sent> | <bloque>)} [else (<sent> | <bloque>)] Donde <expres_log> es una expresión lógica que ha de ir entre paréntesis, y <sent> es una sentencia terminada en punto y coma (;), y <bloque> es un bloque de sentencias entre llaves ({}). Como se observa, esta sintaxis incluye las posibles variantes de selección simple, selección binaria e incluso el anidamiento de selecciones. Ejemplo: if (i < 10) { cout << "Es menor que 10" << endl; } else if (i > 20) { cout << "Es mayor que 20" << endl; } else cout << "Entre 10 y 20" << endl; Sentencia switch La sentencia switch es la sentencia de C++ que se utiliza para implementar la selección múltiple. Esta sentencia es especialmente útil cuando la selección se basa en el valor de una variable o expresión de un tipo simple ordinal denominada "selector". La notación BNF de la sentencia es la siguiente: <sent_case>::= switch '(' <selector> ')' '{' {<rama>} [default : {<sent>}] '}' <rama> ::= {<etiqueta>} {<sent>} [break;] <etiqueta> ::= case <exp_const> : Donde <selector> es una expresión ordinal, <sent> es una sentencia o secuencia de sentencias terminadas en punto y coma (;), y <exp_const> es una expresión constante del mismo tipo que la expresión ordinal del selector. Si no se indica la instrucción "break;", la ejecución continuará en la primera sentencia de la siguiente cláusula "case". La cláusula "default" es opcional, si no se indica y el resultado de evaluar el selector es un valor no presente en ninguna rama, no se ejcutará ninguna sentencia. Ejemplo: switch (a) { case 'a' : cout << "Es una a" << endl; break; Pág. 7 Introducción a los Computadores Práctica 2 case 'b' : case 'c' : cout << "Es b o c" << endl; break; default : cout << "No es a,b,c" << endl; } EJEMPLO. El estilo de codificación que usaremos para las sentencias de selección if y switch se ilustra en el siguiente ejemplo de programa C++ completo. /*---------------------------------------------------------------| Autor: | | Fecha: Versión: 1.0 | |-----------------------------------------------------------------| | Descripción del Programa: animales.cpp, selección múltiple. | | | | Este programa recoge una letra del teclado e imprime el nombre | | de un animal que empieza por dicha letra. | | | | ----------------------------------------------------------------*/ // Incluir E/S y Librerías Standard #include <iostream> #include <cstdlib> using namespace std; // Zona de Declaración de Constantes // Zona de Declaración de Tipos // Zona de Cabeceras de Procedimientos y Funciones // Programa Principal int main() { // Zona de Declaración de Variables del Programa principal char c; // Zona de instrucciones cout << "Dame una letra y te dire el nombre " << "de un animal que comience por ella : "; cin >> c; if (c >= 'a' && c <= 'z') { switch (c) { case 'a': cout << "aramillo, oveja salvaje del Caribe." << endl; break; case 'b': cout << "babirusa, cerdo salvaje de Malasia." << endl; break; case 'c': cout << "chascalote, ballena gigante del Amazonas." << endl; break; case 'd': cout << "destemplat, pinguino rojo de Kenia." << endl; break; case 'e': Pág. 8 Introducción a los Computadores Práctica 2 cout << "equigobo, camello siberiano." << endl; break; default: cout << "Humm ... ese no me lo se." << endl; } } else if (c >= 'A' && c <= 'Z') cout << "Solo me trato con letras minusculas. Lo siento." << endl; else cout << "Me temo que no te entiendo." << endl; system("Pause"); return 0; // Hacer una pausa // Valor de retorno al S.O. } // Implementación de Procedimientos y Funciones El operador condicional Es el único operador con 3 operandos (ternario) y sustituye a una sentencia de selección binaria. a ? b : c Donde a es una expresión lógica y b y c son expresiones del mismo tipo. Si a es true, el resultado de la expresión a ? b : c es b. Si a es false el resultado es c Ejemplo del máximo de dos números: max = (x > y) ? x : y; En otros lenguajes (p.e.: Pascal) es necesario usar una sentencia de selección binaria: if x > y then max := x else max := y Sentencias de iteración en C++. C++ soporta tres tipos de estructuras de iteración: los bucles while, do-while y for. Éstos se corresponden con los esquemas de iteración vistos en pseudolenguaje. Sentencia while Se corresponde con el esquema MIENTRAS del pseudolenguaje. La notación BNF de la sentencia while es la siguiente: <sent_while> ::= while '(' <expres_log> ')' (<sent> | <bloque>) Un bucle while tiene una condición de control o expresión lógica <expres_log>, que ha de ir encerrada entre paréntesis, y que controla la secuencia de repetición. El estilo de codificación que usaremos para esta sentencia es el siguiente: while (<expres_log>) { <sec_sent> } Ejemplo: while (i < 10) { cout << i << endl; i ++; Pág. 9 Introducción a los Computadores Práctica 2 } Sentencia do-while Se corresponde con el esquema REPETIR del pseudolenguaje. La notación BNF de la sentencia do-while es la siguiente: <sent_do-while> ::= do (<sent> | <bloque>) while '(' <expres_log> ')'; En esta sentencia, el cuerpo del bucle se ejecuta hasta que sea FALSA la expresión lógica <expres_log> (que ha de ir encerrada entre paréntesis). Por tanto, al igual que en el bucle while el cuerpo del bucle se ejecuta mientras la expresión lógica sea cierta. Esto supone una diferencia con la sentencia REPETIR del pseudolenguaje en la que el cuerpo del bucle se ejecutaba hasta que la expresión lógica fuese verdadera. El bucle do-while también se denomina post-prueba, ya que la expresión lógica se comprueba cada vez después de la ejecución del cuerpo del bucle. El estilo de codificación que usaremos para esta sentencia es el siguiente: do { <sec_sent> } while (<expres_log>); El cuerpo de una sentencia do-while siempre se ejecuta al menos una vez. Cuando esto deba ocurrir en un programa (el cuerpo del bucle tenga que ejecutarse una o más veces), es conveniente el uso de la sentencia do-while en lugar de la sentencia while. Ejemplo: do { cin >> a; } while (a != 'c'); Sentencia for Se corresponde con el esquema PARA del pseudolenguaje. Su notación BNF es la siguiente: <sent_for> ::= for '(' <inicialización>; <condición>; <actualización> ')' (<sent> | <bloque>) <inicialización> ::= <ident> = <expresion_constante> donde <inicializacion> es la parte en la que se inicializa la variable de control del bucle, <condición> es una expresión lógica que hace que se ejecute el cuerpo del bucle mientras que dicha expresión sea cierta, y <actualización> es una expresión que incrementa o decrementa la variable de control del bucle. Las partes <inicialización>, <condición> y <actualización> son expresiones pero ninguna de ellas es obligatoria. Las expresiones pueden ser cualesquiera válidas en C, incluyendo funciones, distintas variables en cada una, etc... El bucle for de C++ es mucho más potente que la sentencia PARA y por ello es la estructura de bucle más utilizada. El estilo de codificación que usaremos para esta sentencia es el siguiente: for (<inicialización>; <condición>; <actualización>) { <sec_sent> } Ejemplo: for (i = 1; i <= 10; i ++) { Pág. 10 Introducción a los Computadores Práctica 2 cout << i << endl; } La semántica de esta construcción puede darse aproximadamente en términos de la del bucle while de la siguiente manera: <inicialización>; while (<condición>) { <sentencias> <actualización>; } Ejemplo: int main () { int x; for (x = 1; x <= 100; cout << x ++ << endl); } Anidamientos de bucles Una sentencia dentro de un bucle puede ser a su vez otro bucle (del mismo o distinto tipo). Para diseñar una estructura iterativa anidada debemos comenzar diseñando la más exterior. Cuando llega el momento de diseñar el proceso que se repite, el bucle exterior incluirá al bucle anidado, que pasa a ser diseñado como se haría con cualquier otro. Esta forma de actuar debe repetirse para cualquier número de niveles de anidamiento. Ha de tenerse en cuenta que el comienzo y final de un bucle anidado deben estar dentro del mismo bucle que lo anida. Otras consideraciones respecto de los bucles Bucle infinito while (true) { ... } for (; ; ) { ... } Operador coma Es el operador con menor precedencia de todos. Se puede utilizar para separar varias expresiones en cualquier lugar donde es legal escribir una expresión. for (i = 0, j = 100; i != 10; i ++, j -= 10) Las expresiones se evaluan de izquierda a derecha. (i++, j = i) El valor de una expresión con operadores coma es el valor de la expresión más a la derecha. while (i < 100) sum += i, i ++; Pág. 11 Introducción a los Computadores Práctica 2 EJEMPLO. El estilo de codificación que usaremos para las sentencias de iteración while, do … while y for se ilustra en el siguiente ejemplo. /*---------------------------------------------------------------| Autor: | | Fecha: Versión: 1.0 | |-----------------------------------------------------------------| | Descripción del Programa: rombo.cpp, enteros,caracteres,bucles | | | | Escribe un algoritmo que lea un número natural N y un carácter | | por teclado. La salida debe ser un rombo compuesto del carácter | | y de la anchura que especifica el número N. Por ejemplo, si N | | es 5 y el carácter es *, el rombo sería: | | | | * | | *** | | ***** | | *** | | * | | ----------------------------------------------------------------*/ // Incluir E/S y Librerías Standard #include <iostream> #include <cstdlib> using namespace std; // Zona de Declaración de Constantes // Zona de Declaración de Tipos // Zona de Cabeceras de Procedimientos y Funciones // Programa Principal int main() { // Zona de Declaración de Variables del Programa principal int x, y, z, i; char c; // Zona de instrucciones cout << "Programa que dibuja un rombo en pantalla." << endl; do { // Ancho del rombo cout << "Introducir un numero impar: "; cin >> z; } while (z % 2 == 0); cout << "Introducir un caracter: "; cin >> c; cout << endl; i = 1; // Dibuja triángulo superior while (i <= z) { x = (z - i) / 2; for (y = 1; y <= x; y ++) cout << " "; for (y = 1; y <= i; y ++) cout << c; cout << endl; i += 2; } Pág. 12 Introducción a los Computadores Práctica 2 i = z - 2; // Dibuja triángulo invertido inferior while (i >= 1) { x = (z - i) / 2; for (y = 1; y <= x; y ++) cout << " "; for (y = 1; y <= i; y ++) cout << c; cout << endl; i -= 2; } system("Pause"); return 0; // Hacer una pausa // Valor de retorno al S.O. } // Implementación de Procedimientos y Funciones Sentencias break y continue Las sentencias break y continue se utilizan en el ámbito de las sentencias while, for y do y únicamente pueden estar contenidas en los cuerpos de los bucles. La sentencia break se utiliza para salir del bucle que se está ejecutando. La ejecución continúa en la primera instrucción tras la estructura de bucle. break; La sentencia continue finaliza la ejecución de la iteración actual del bucle en curso. Se continúa con la ejecución del bucle pero se saltan las sentencias que quedaban en el cuerpo del bucle para esa iteración. continue; NOTA: NO SE PERMITE EL USO DE LAS SENTENCIAS break O continue EN UN BUCLE (for, do-while o while) NI LA MODIFICACIÓN DE LA VARIABLE DE CONTOL DEL BUCLE for DENTRO DEL MISMO. Pág. 13