Resumen
Esta clase abre la quinta unidad del curso, dedicada a las funciones. Explica para qué sirve la unidad: enseñar a descomponer un problema en partes con nombre, cada una con una interfaz y un contrato, y a resolver ciertos problemas reduciéndolos a una instancia menor de sí mismos, por recursión; presenta sus cuatro clases y el hilo que las une; recuerda lo que la unidad da por sabido, sobre todo los bucles y sus invariantes de la unidad 4; formula el problema que la unidad resuelve, el de un programa que repite el mismo cálculo copiado y que, por un descuido en la copia, responde mal sin que el compilador diga nada; anticipa el contrato (la precondición y la poscondición) como la forma con que la unidad especificará cada parte; y muestra adónde conduce, en las unidades siguientes y en el curso Programación en C++ II.
Objetivos de aprendizaje
- Describir la secuencia de contenidos de la unidad y explicar qué aporta cada clase a la siguiente.
- Recordar los algoritmos de la unidad 4 (la traza de un bucle, su invariante y su variante) y repasarlos si hace falta.
- Anticipar, con un ejemplo, la idea de contrato: lo que una parte del programa exige a quien la usa y lo que le garantiza a cambio.
- Reconocer qué se espera saber hacer al terminar la unidad, y distinguirlo de lo que se aprenderá en las unidades siguientes.
Evaluación de entrada
Antes de recorrer la unidad conviene medir el punto de partida. Esta evaluación es una autoevaluación: no se califica, y su único propósito es orientar el estudio. Las cinco primeras preguntas comprueban lo que la unidad da por sabido: la traza de un bucle, su invariante, la precondición de una especificación, la copia de un valor en la inicialización y la búsqueda, dentro de un programa de la unidad 4, de un cálculo con entradas y salidas propias. Las cinco siguientes tocan, en el orden de las clases, las ideas centrales de la unidad: la pila de llamadas, el paso de un argumento, la separación entre el cálculo y la presentación, la definición recursiva del factorial y la ejecución de una función que se llama a sí misma. Nadie está obligado a acertarlas todavía, y en algunas «todavía no lo sé» es una respuesta honesta: cada respuesta, acertada o no, explica el punto y nombra la clase que lo trata. Las mismas destrezas se vuelven a medir al final, en la clase de síntesis.
Antes de comenzar la unidad, mide tu punto de partida. Es una autoevaluación breve: no se califica y su resultado se guarda solo en tu navegador.
Pregunta 1De unidades anteriores¿Qué escribe
int n{305}; int c{1}; while (n >= 10) { n = n / 10; ++c; } std::println("{}", c);?Cuenta las vueltas y olvida quecempieza en 1.Da una vuelta de más: con la condiciónn >= 10ya es falsa.Confunde el contador con el valor dendespués de la primera vuelta.Pregunta 2De unidades anterioresEn el bucle
int total{0}; int k{1}; while (k <= n) { total += k; ++k; }, con , ¿qué relación vale cada vez que se evalúa la condición?Vale en mitad de la vuelta, después de sumar y antes de incrementar, pero no cuando se evalúa la condición.Vale solo al terminar: es la poscondición, no el invariante.Es la condición del bucle, y es falsa justamente al salir; un invariante vale también entonces.Vale al comienzo, con la suma vacía y ; y si vale antes de una vuelta, vale después, porque la vuelta suma y después lo incrementa. Al salir, , y el invariante da la suma de 1 a . La clase Recursión justifica sus funciones con el mismo razonamiento por inducción.Repasar: Diseñar bucles correctos
Pregunta 3De unidades anterioresLa especificación de la división dice: «dados enteros y , obtener y con y ». ¿Cuál es su precondición?
Confunde la precondición con la poscondición: eso es lo que cumple el resultado, no lo que se exige a los datos.Es una condición sobre la salida, no sobre la entrada.Con no existe ningún con : el problema no tiene solución, y la precondición lo excluye.La precondición es lo que se exige a los datos para que el problema tenga solución; la poscondición, lo que el resultado cumple. La unidad convierte esta pareja en el contrato de cada función: la precondición obliga a quien llama, y la poscondición, a la función.Repasar: Del problema al algoritmo
Pregunta 4De unidades anterioresTras
int a{3}; int b{a}; b = 7;, ¿cuánto valea?Cree quebyaquedan unidas para siempre; la inicialización copia el valor, no la casilla.Confunde la copia con una variable sin inicializar:arecibió 3 y nada lo cambió.La inicializaciónint b{a}copia en la casilla debel valor queatenía; después, las dos casillas son independientes. La clase Parámetros y alcance muestra que un parámetro se inicializa del mismo modo, con una copia del argumento, y enseña la otra posibilidad: un segundo nombre para la misma casilla.Repasar: Variables y memoria
Pregunta 5De unidades anterioresEl programa de la clase 4.4 que escribe los primos menores que 50 tiene un bucle que recorre los candidatos y, dentro, otro que prueba sus divisores. ¿Qué parte es un cálculo con entradas y salidas propias, que convendría nombrar?
Confunde la entrada y la salida del programa entero con las de un cálculo interior.Es una sentencia, no un cálculo con sentido propio: no tiene una entrada y un resultado que alguien quiera usar.Confunde un dato con una tarea: la variable guarda el resultado del cálculo, pero no es el cálculo.El bucle interior no depende de nada más que del candidato, y su resultado es un sí o un no. Darle nombre permite leer el bucle exterior como su especificación: «para cada candidato, si es primo, escribirlo». La clase Diseñar con funciones reescribe así ese programa.Repasar: Algoritmos numéricos
Pregunta 6Un programa empieza en
main;mainllama a una funcióng, ygllama a otra funciónh. Mientrashse ejecuta, ¿qué llamadas están en curso?Cree que quien llama desaparece al llamar; en cambio, espera para continuar donde se detuvo.Cree quegterminó al llamar ah; terminará cuandohle devuelva el control.Es una respuesta honesta: la clase 5.1 lo explica con una figura de la pila.Pregunta 7Con la función
int f(int x) { x = x + 1; return x; }, ¿qué escribeint a{3}; int b{f(a)}; std::println("{} {}", a, b);?Cree que la función modifica el argumento; por omisión, recibe una copia.Cree que el cambio dexno alcanza ni siquiera al valor devuelto.Cree que un parámetro no puede modificarse; puede, salvo que se declareconst.El parámetroxes una variable defque se inicializa con una copia del argumento: la función cambia la copia y devuelve 4, yaconserva su 3. Es el paso por valor, el modo por omisión de C++.Repasar: Parámetros y alcance
Pregunta 8Un programa lee una fecha y debe escribir su día de la semana. ¿Qué descomposición separa el cálculo de la presentación?
Mezcla dos tareas: lo calculado no puede reutilizarse ni compararse con un valor esperado.Separa las tareas, pero las comunica por un efecto oculto: quien lee la llamada no ve de dónde sale el dato.Es una respuesta honesta: la clase 5.3 enseña a decidir qué funciones escribir.Así el cálculo se prueba con números, sin mirar la pantalla, y puede servir a otro programa que escriba el resultado de otra manera. La clase 5.3 llama a este criterio «una función, una tarea».Repasar: Diseñar con funciones
Pregunta 9¿Cuál de las definiciones siguientes define para todo natural ?
Sin caso base, la definición no se detiene nunca: remitiría a , y así sin fin.Define bien para , pero deja sin definir , que vale 1.Define a partir de sí mismo: la definición es circular y no reduce el problema.Pregunta 10Con
int f(int n) { if (n == 0) { return 0; } return n + f(n - 1); }, ¿qué escribestd::println("{}", f(3));?Cree que se ejecuta una sola llamada, o confunde el argumento con el resultado.Cree que elreturn 0del caso base es el resultado de toda la cadena; es solo el de la última llamada.El nombre de la función se conoce desde su cabecera, y puede usarse en su propio cuerpo.f(3)espera af(2), que espera af(1), que espera af(0); esta devuelve 0, y al volver se suman 1, 2 y 3. La función calcula , la misma suma que el bucle de la segunda pregunta.Repasar: Recursión
Cargando el contenido…