Capítulo 6. Estructura de control repetitiva. 1. Introducción. 2. Estructura repetitiva ‘mientras’ (while). 3. Estructura repetitiva ‘repetir’ (repeat). 4. Estructura repetitiva ‘para’ (for). 5. Anidamiento de repetitivas. 6. Ejemplos modelos de bucles. 7. Variables auxiliares. 7.1. Contador. 7.2. Acumulador. 7.3. Interruptor. 1 1. Introducción. Una estructura repetitiva se usará para ejecutar un grupo de instrucciones un número determinado de veces. Ese número de veces se controlará por medio de una expresión booleana o condición, cuyo valor será verdadero o falso. Estas estructuras se suelen denominar bucles. Veamos los distintos tipos. 2. Estructura repetitiva ‘mientras’ (while). En pseudocódigo esta estructura se escribe de la forma: ... mientras (condición) Sentencia1 Sentencia2 ... finmientras ... Al comenzar la ejecución del ‘mientras’, la condición es evaluada. Si su valor es verdadero, se ejecutan las sentencias colocadas entre mientras y finmientras (sentencias del bucle); la línea finmientras provoca un salto hacia arriba, a la línea mientras de nuevo y se vuelve a evaluar la condición. Si su valor es verdadero otra vez, se realizan las mismas acciones, y así sucesivamente. Si en alguna de las repeticiones, al evaluar la condición su valor es falso, la ejecución salta a la sentencia siguiente al finmientras. Si al evaluar la condición por primera vez resulta ser falsa, las sentencias del bucle no se ejecutan ni una sola vez. No debe olvidarse que la condición debe estar inicializada, es decir que todas las variables que formen parte de la misma deben tener los valores iniciales adecuados. Además dentro del bucle siempre debe existir alguna instrucción que afecte o modifique (actualice) la condición, ya que si no es así, una vez dentro del bucle no se podría salir, siendo un bucle infinito, porque la condición seguiría siendo verdadera en todas las repeticiones. Podría por tanto escribirse: ... <Inicializar condición> mientras (condición) Sentencia1 Sentencia2 ... <Actualizar condición> finmientras ... En C la sintaxis de esta estructura es: ... while (condición) 2 { Sentencia1; Sentencia2; ... } //equivale al finmientras ... Ej. //Bucle que se repite 10 veces. numero = 1; //inicializa condición while (numero <= 10) { ... numero = numero + 1; //actualiza condición } 3. Estructura repetitiva ‘repetir’ (repeat). En pseudocódigo esta estructura se escribe de la forma: ... repetir Sentencia1 Sentencia2 ... hasta (condición) ... Al comenzar la estructura ‘repetir’, se ejecutan las sentencias colocadas entre repetir y hasta (sentencias del bucle) y después se evalúa la condición. Si su valor es falso, se realiza un salto hacia arriba, hasta la línea repetir, y se ejecutan las sentencias del bucle de nuevo. Si en alguna de las repeticiones, al evaluar la condición su valor es verdadero, la ejecución continúa por la sentencia siguiente a la línea hasta. Como vemos, las sentencias del bucle siempre se ejecutan al menos una vez. En este tipo de repetitiva también ocurre como en la anterior, es decir antes de evaluar la condición por primera vez debe estar inicializada y además dentro del bucle debe actualizarse dicha condición, para no entrar en un bucle infinito. En algunos lenguaje existe la sentencia ‘repeat-until’, lo cual no ocurre en C, en el que esta sentencia adopta la sintaxis: ... do { Sentencia1; Sentencia2; ... } while (condición); ... 3 Ello implica que el bucle finaliza cuando la condición es falsa, ya que un mientras expresa la idea contraria a un hasta. Ej. //Bucle que suma notas tecleadas, hasta que sea 0. do { scanf(“%d”, &nota); //inicializa y actualiza suma += nota; //la condición }while (nota != 0); 4. Estructura repetitiva ‘para’ (for). En pseudocódigo esta estructura se escribe de la forma: ... para <Variable> de <VI> a <VF> con incremento <Inc> Sentencia1 Sentencia2 ... finpara ... Este bucle se diferencia de los anteriores porque se repite un número fijo de veces. La <Variable> toma inicialmente el valor <VI> (valor inicial), si ese valor es menor o igual que <VF> (valor final) se ejecutan las sentencias del bucle. A continuación la <Variable> se incrementa en el valor <Inc> y si su valor vuelve a ser menor o igual que <VF>, se ejecutan de nuevo las sentencias. Se vuelve a incrementar la <Variable> en el valor <Inc>, y así sucesivamente, hasta que el valor de <Variable> sea mayor que el valor <VF>, en cuyo caso el programa continúa con la sentencia colocada después del finpara. Como se ve en esta sentencia, en la misma línea del para se asegura la iniciaización de la condición (VI) y la actualización de la condición (Inc). La sentencia para anterior es equivalente al siguiente while: ... <Variable> = <VI> mientras ( <Variable> <= <VF> ) Sentencia1 Sentencia2 ... <Variable> = <Variable> + Inc finmientras ... En C la sintaxis equivalente al para es: ... for (<Vari> = <VI>; <Vari> <= <VF>; <Vari> += Inc) { 4 Sentencia1; Sentencia2; ... } ... Aunque la sentencia for tiene un uso más amplio que el para, ya que realmente en la línea for se pueden colocar tres expresiones cualesquiera separadas por punto y coma, incluyendo la expresión nula. Es decir: ... for (Expresión1; Expresión2; Expresion3) { Sentencia1; Sentencia2; ... } ... El funcionamiento de ese bucle es el siguiente: se ejecuta la expresión1; después se evalúa la expresión2, y si es cierta se ejecutan las sentencias del bucle; al llegar a la llave cerrada }, se salta hacia arriba y se ejecuta la expresión3; se vuelve a evaluar la expresión2, y si es cierta, se ejecutan las sentencias del bucle de nuevo; y así sucesivamente, hasta que expresión2 sea falsa, en cuyo caso se continúa por la sentencia colocada después del bucle. Por tanto, con la sentencia for de C se puede implementar cualquier bucle, ya sea mientras, repetir o para. La expresión1 se suele usar como inicialización de la condición, la expresión2 como condición y la expresión3 como actualización de la condición. Ej. //Bucle que se ejecuta 10 veces for (numero = 1; numero <= 10; numero++) { Sentencia1; ... } ... //Bucle que suma notas tecleadas, hasta que sea 0. suma = 0; for (scanf(“%d”, &nota);nota != 0; scanf(“%d”, &nota)) suma += nota; //Bucle que suma notas tecleadas, hasta que sea 0. suma = 0; scanf(“%d”, &nota) for ( ;nota != 0; ) { 5 suma += nota; scanf(“%d”, &nota) } //Bucle dependiente de 2 variables. for (x=0, y=0; x+y < 100; x++, y+=2) { Sentencia1; ... } //Bucle que finaliza al teclear N. for (car = getche(); car != ‘N’; car = getche()) { Sentencia1; ... } 5. Anidamiento de repetitivas. Como cualquier otra estructura de control, las repetitivas también pueden anidarse, es decir colocar una dentro de otra, lo cual puede hacerse repetidas veces. Una estructura repetitiva es otra sentencia más, por lo tanto puede colocarse en cualquier punto previo marcado como sentencia. El único criterio a seguir al anidar estructuras, como ya se dijo para las alternativas, es que debe cerrarse siempre la estructura interna antes de hacerlo la externa. O sea, una llave cerrada } cerrará siempre a la estructura más cercana hacia arriba que esté abierta. Veamos un ejemplo genérico: ... while (condición) { Sentenci1; for (Exp1; Exp2; Exp3) { Sentencia2; Sentencia3; ... if (condición) Sentencia4; else Sentencia5; } //cierra al for Sentencia6; } //cierra al while ... 6. Ejemplos modelos de bucles. 6 Vamos a comentar algunos casos muy típicos a la hora de usar estructuras repetitivas. Caso 1. Realizar una serie de sentencias hasta que se responda ‘N’ a la pregunta “Desea Continuar (S/N)?”. resp = getche(); while (resp != ‘N’) { Sentencia1; ... resp = getche(); } También podría escribirse de la forma: while ((resp = getche()) != ‘N’) { Sentencia1; ... } Con for sería: for (resp = getche(); resp != ‘N’; resp = getche()) { Sentencia1; ... } Caso 2. Teclear una serie de datos, por ejemplo CODIGO, NOMBRE y NOTA, hasta que el primer dato a teclear sea 0, o sea el CODIGO tecleado sea 0. scanf(“%d”, &codigo); fflush(stdin); for ( ;codigo!=0; scanf(“%d”, &codigo), fflush(stdin)) { scanf(“%19[\n]”, nombre);fflush(stdin); scanf(“%f”, &nota);fflush(stdin); ... } Con while sería: scanf(“%d”, &codigo); fflush(stdin); while (codigo != 0) { scanf(“%19[^\n]”, nombre);fflush(stdin); scanf(“%f”, &nota);fflush(stdin); ... ... scanf(“%d”, &codigo); fflush(stdin); 7 } Caso 3. Repetir un grupo de sentencias un número determinado de veces, por ejemplo teclear los datos de 30 alumnos. for ( contador = 1; contador <= 30; contador++) { scanf(“%d”, &codigo);fflush(stdin); scanf(“%19[^\n]”, nombre);fflush(stdin); scanf(“%29[^\n]”, direccion);fflush(stdin); ... } 7. Variables auxiliares. Algunas variables cumplen funciones particulares dentro del programa, por lo que se les da un nombre especial. Veamos cuales son. 7.1. Contador. Un contador es una variable que se usa para contar algún acontecimiento del programa, por lo que generalmente se incrementan de 1 en 1. Estas variables deben inicializarse, generalmente a cero, para comenzar a contar. A continuación, cada vez que ocurra el evento a contar, se incrementará en una unidad. contador = 0 //Inicialización contador = contador + 1 //Incremento Realmente toda variable que aparezca, en una asignación (=), a ambos lados del signo = deberá inicializarse. Por ejemplo, si se desea ejecutar un bucle un número determinado de veces, se usará un contador para avisar cuando se llegue a ese número: // En pseudocódigo: contador = 1 //En este caso se inicializa a 1. mientras (contador <= numero) ... contador = contador + 1 finmientras Otro ejemplo podría ser contar cuántos números son positivos de 100 tecleados: // En C: contador = 0 for (i=1; i <= 100; i++) { scanf(“%d”, &numero); if (numero > 0) contador++; } 8 Como vemos, en ese ejemplo hay dos contadores: i cuenta las vueltas del bucle, mientras que contador cuenta cuántos números positivos se han tecleado. 7.2. Acumulador. Un acumulador es una variable que se usa para ir acumulando elementos sucesivos con una misma operación, generalmente suma o producto. Al igual que los contadores, deben inicializarse antes de comenzar a acumular. Se inicializan a 0 si la operación de acumular es la suma y se inicializan a 1 si la operación es el producto. Y además estas variables deben ir acumulando. Acumulador = 0 //Inicialización Acumulador = Acumulador + Numero //Acumula el numero Por ejemplo, sumar 10 notas tecleadas: //En pseudocódigo: suma = 0 para i de 1 a 10 con Incremento 1 Leer nota suma = suma + nota finpara Otro ejemplo podría ser multiplicar los 15 primeros números: //En C: producto = 1; contador = 1; while (contador <= 15) { producto *= contador; contador++; } 7.3. Interruptor. Un interruptor es una variable que toma dos valores, verdadero o falso. Se puede usar para recordar en un punto del programa, si previamente ocurrió algún evento. Por ejemplo, teclear 10 notas e indicar al final si alguna ha sido un 10: //En pseudocódigo: interruptor = 0 // Falso para i de 1 a 10 con Incremento 1 Leer nota si (nota = 10) interruptor = 1 finsi finpara si (interruptor = 1) 9 Escribir “SI ha habido algún 10” finsi Otro uso del interruptor es tomar los valores verdadero y falso alternativamente en un bucle, para lo cual se emplea el operador NOT de la forma siguiente: interruptor = NOT interruptor En C sería: interruptor = ! interruptor; Por ejemplo, sumar los números pares y los impares por separado, entre el 1 y el 1000: // En C: interruptor = 1; for (suma_par=0, suma_impar=0, i = 1; i <= 1000; i++) { if (interruptor) suma_impar += i; else suma_par += i; interruptor = !interruptor; } 10 EJERCICIOS - CAPITULO 6: Realizar los algoritmos en pseudocódigo que solucionen las siguientes tareas, pasándolos después a lenguaje C: 1. Teclear el nombre de un alumno, su especialidad y sus 11 notas, visualizando a continuación su nota media. 2. Visualizar la suma de los números del 1 al 1000. Modificar este programa para que funcione desde el 1 hasta un número tecleado. 3. Visualizar el producto de 10 números tecleados. 4. Visualizar el resultado de una operación tecleada (suma, resta, producto, división) sobre 2 números tecleados. El programa debe solicitar operación y 2 números cada vez que se responda ‘S’ a la pregunta “Hacer operación (S/N)?”. 5. Teclear una serie de números enteros, hasta que se teclee un cero, y visualizar cuántos han sido pares y cuántos impares. 6. Teclear el nombre de alumno y su nota entera (0 a 10) para 10 alumnos. Para cada alumno deberá visualizarse la nota de la forma: Muy Deficiente(0,1,2); Insuficiente (3,4); Suficiente (5); Bien (6); Notable (7,8); Sobresaliente (9,10). 7. Teclear DNI, nombre y edad de alumnos, hasta que el DNI tecleado sea cero. Visualizar para cada alumno si es mayor de edad o no. 8. Teclear el nombre y las 11 notas de una serie de alumnos, hasta que se responda ‘N’ a la pregunta “Teclear alumno (S/N)?”. Deberá visualizarse el nombre y la nota media para cada alumno. 9. Teclear números hasta que se responda ‘N’ a la pregunta “Teclear número(S/N)?”. Visualizar si es primo cada número tecleado. 10. Teclear números hasta que se teclee un cero y visualizar los divisores de cada número tecleado. 11. Teclear el dni (numérico) y la edad de una serie de personas hasta responder ‘N’ a la pregunta “Introducir datos (S/N)?”. Visualizar al final el dni y la edad de la persona de mayor edad. 12. Visualizar el producto de los números pares e impares por separado desde el 1 hasta cada uno de los números que se tecleen, hasta que sea cero el número tecleado. 13. Introducir una serie de caracteres hasta que se pulse la tecla “Escape” y visualizar cuántas veces se ha tecleado cada una de las vocales. 11