Resumen
Esta clase abre la octava y última unidad del curso, dedicada a los programas más grandes. Explica su propósito: organizar, verificar y depurar programas que ya no caben en un archivo ni en la cabeza; presenta sus tres clases y el hilo que las une, que cierra el círculo abierto en la primera clase del curso (especificar, construir, verificar); recuerda lo que la unidad da por sabido, que es el curso entero; formula el problema que la unidad resuelve, el de un programa de un solo archivo que funciona con los datos con que se lo probó y calla un error en el borde de su especificación; anticipa la diferencia entre probar y demostrar; y muestra adónde conduce, en el proyecto final y en 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, con un ejemplo, la diferencia entre declarar y definir una función, el contrato que la especifica y las etapas (compilación y enlace) que convierten varios archivos en un programa.
- Anticipar, con un ejemplo, la diferencia entre probar un programa con algunos casos y demostrar que es correcto para todos los admisibles.
- Reconocer qué se espera saber hacer al terminar la unidad y el curso, y distinguirlo de lo que se aprenderá en Programación en C++ II.
Evaluación de entrada
Antes de recorrer la unidad conviene medir el punto de partida. Esta evaluación no se califica: orienta el estudio. Las siete primeras preguntas comprueban lo que la unidad da por sabido (declarar y definir, la precondición, el contrato de una función de la unidad 6, los mensajes del enlazador, los casos de una búsqueda binaria, la tabla de traza y la lectura fuera de un vector); las tres siguientes tocan, en el orden de las clases, las ideas centrales de la unidad, y en ellas «todavía no lo sé» es una respuesta honesta. Cada respuesta explica el punto y nombra la clase que lo trata; las mismas destrezas se vuelven a medir 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é hace la línea
int gcd(int a, int b);escrita antes demain?Confunde declaración y definición: sin cuerpo no hay nada que ejecutar, y ninguna función se ejecuta por estar escrita, sino al ser llamada.Confunde declarar con invocar: una llamada no lleva los tipos de los parámetros.Ignora que al compilador le basta la firma para comprobar una llamada; la falta del cuerpo, si nadie lo escribe, la descubre el enlazador, no el compilador.Una declaración basta para que el compilador compruebe cada llamada; la definición, con el cuerpo, puede estar más abajo o en otro archivo. Toda la clase Varios archivos y bibliotecas propias descansa en esta separación: la cabecera declara, el archivo de implementación define.Repasar: Funciones
Pregunta 2De unidades anterioresLa función
toBase(n, base)tiene la precondición «n >= 0y2 <= base <= 10». ¿Quién debe garantizarla?Confunde la precondición con la validación de entradas: validar es tarea de la frontera del programa, no de cada función.Cree que los comentarios se verifican; el compilador los descarta.No ve que el contrato reparte obligaciones; sin él, nadie sabe quién se equivocó cuando algo falla.La precondición es la parte del contrato que obliga a quien llama; a cambio, la función garantiza su poscondición. Si la precondición se viola, la función no promete nada. La clase Probar programas enseñará a comprobarla conassertmientras el programa se desarrolla.Repasar: Funciones
Pregunta 3De unidades anterioresLa función
binarySearch(values, target)de la clase 6.4 devuelve una posición detargetovalues.size()si no está. ¿Cuál es su precondición?Con el vector vacío el bucle no da ninguna vuelta y la función devuelve 0, que esvalues.size(): el caso está cubierto por la poscondición.La función informa la ausencia; exigir la presencia la haría inútil.Con repetidos la función devuelve una de las posiciones del valor, lo que la poscondición admite.Cada vuelta descarta la mitad del tramo comparando con el elemento central, y eso solo es válido si el vector está ordenado. Con datos desordenados la función responde, sin aviso, algo falso. La precondición se escribe en el contrato, donde quien llama la ve.Repasar: Buscar y ordenar
Pregunta 4De unidades anterioresUn programa compila sin errores y, al construir el ejecutable, aparece
undefined reference to `tetrahedral(int)'. ¿Qué etapa falló?No distingue los mensajes del compilador, que citan un archivo y una línea, de los del enlazador, que citan objetos y nombres.El programa no llegó a existir: sin ejecutable no hay ejecución.Un#includeausente producewas not declared in this scopeal compilar, no este mensaje.El compilador aceptó cada llamada porque vio una declaración; el enlazador buscó la definición en todos los objetos y en las bibliotecas, y no la encontró. La clase Varios archivos y bibliotecas propias explica sus causas habituales: un archivo que no se compiló, o una declaración copiada con otro tipo.Repasar: Programas, compiladores y C++
Pregunta 5De unidades anteriores¿Cuál de estos conjuntos de casos pone mejor a prueba una búsqueda binaria?
Confunde cantidad con cobertura: nunca prueba la ausencia ni los bordes, donde suelen estar los errores.Un caso que ya pasó es el que menos probabilidad tiene de descubrir algo nuevo.Son infinitos, o astronómicamente muchos dentro de los límites del tipo: probar exige elegir.Cada caso ejercita un borde distinto del tramo : el tramo vacío desde el comienzo, el que se reduce a un elemento, los extremos y las tres maneras de no estar. Elegir los casos desde la especificación, por regiones y bordes, es el tema de la clase Probar programas.Repasar: Buscar y ordenar
Pregunta 6De unidades anteriores¿Qué valen
aybdespués deint a{0}; int b{1}; for (int i{0}; i < 4; ++i) { const int t{a + b}; a = b; b = t; }?Cuenta una vuelta de más: coni < 4el cuerpo se ejecuta cuatro veces, no cinco.Cuenta una vuelta de menos, el error por uno simétrico.Olvida quetguarda la suma antes de queacambie; sin la variable auxiliar, el resultado sería ese.La tabla de traza, vuelta por vuelta, da : cuatro vueltas, conide 0 a 3. Es la tabla que el depurador llena por quien programa, y la clase Depurar programas la usa para juzgar el estado en cada punto de interrupción.Repasar: Bucles
Pregunta 7De unidades anteriores¿Por qué
std::vector<int> v{1, 2}; std::println("{}", v[2]);se detiene con las opciones del curso y, compilado con-O2, puede escribir un número cualquiera?Cree que la optimización repara errores; solo quita comprobaciones y supone que el programa no viola la norma.Invierte el efecto: la comprobación que detiene el programa es la de la biblioteca sin optimizar.Es el error por uno de los índices: los de un vector de dos elementos son 0 y 1.El índice 2 no existe en un vector de dos elementos. Lo que se observa depende del compilador y de las opciones, y por eso las pruebas se ejecutan con todas las comprobaciones activas, como enseña la clase Probar programas.Repasar: Vectores
Pregunta 8Una cabecera con guardas de inclusión define (no solo declara)
double scale(double x), sininline, y la incluyenmain.cppyreport.cpp. ¿Qué ocurre al construir el programa?Cree que las guardas actúan entre archivos; actúan dentro de cada unidad de traducción.Confunde el archivo que se compila con el programa entero: dentro de cada archivo hay una sola definición.Es una respuesta honesta: la clase 8.1 lo muestra con el mensaje real del enlazador.Las guardas impiden que una cabecera entre dos veces en un mismo archivo, pero cada.cppse compila por separado y recibe su copia de la definición: el enlazador encuentra dos. Es la regla de una definición, de la clase Varios archivos y bibliotecas propias.Pregunta 9Una función pasa quinientas pruebas automáticas elegidas con cuidado. ¿Qué se puede afirmar?
Confunde abundancia con demostración; un error en un borde que ningún caso tocó sobrevive a cualquier número de casos interiores.Los casos no son una muestra al azar de los errores posibles, y la frecuencia de aciertos no mide la probabilidad de que el programa esté bien.Es una respuesta honesta: la clase 8.2 empieza por esta pregunta.Una prueba puede mostrar la presencia de un error, nunca su ausencia: afirmar la corrección para todos los casos exige un argumento, como el invariante de la clase 4.3, no una lista de casos. Las pruebas bien elegidas hacen improbable que un error común pase, y por eso valen tanto. La clase Probar programas desarrolla esta distinción.Repasar: Probar
Pregunta 10Un punto de interrupción está en la línea
total += k;, dentro de un bucle, y el programa se detiene allí por tercera vez. ¿Qué indica la línea resaltada?Confunde la detención con el paso ya dado.Confunde el lugar donde se detiene el programa, que elige quien depura, con la causa de la falla.Es una respuesta honesta: la clase 8.3 trata los puntos de interrupción y los pasos.El depurador se detiene antes de la línea marcada; el valor detotalque muestra es el de las dos vueltas anteriores. Confundirlo produce tablas de traza corridas en una fila. La clase Depurar programas lo desarrolla.Repasar: Depurar
Cargando el contenido…