Resumen
Esta clase abre la primera unidad del curso, dedicada a los primeros pasos en la programación con C++. Explica para qué sirve la unidad: llevar a quien nunca ha programado desde un problema enunciado en lenguaje corriente hasta un programa que compila, se ejecuta, lee datos y escribe resultados, sabiendo qué hizo cada herramienta en el camino; presenta sus seis clases y el hilo que las une, desde el algoritmo escrito en español hasta la clasificación de los errores; precisa lo poco que se da por sabido, que es la aritmética escolar, la costumbre de seguir instrucciones escritas y el manejo de archivos y carpetas; formula el problema que la unidad resuelve, el de convertir un cálculo que se sabe hacer a mano en un procedimiento que una máquina ejecuta sin equivocarse y sin cansarse; 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.
- Reconocer los conocimientos previos que el curso supone (operar con enteros y decimales, calcular un cociente y un resto, seguir instrucciones escritas, guardar un archivo en una carpeta determinada) y repasarlos si hace falta.
- Explicar, con un ejemplo, el camino que la unidad enseña a recorrer: del enunciado a la especificación, de la especificación al algoritmo y del algoritmo al programa que se compila y se ejecuta.
- 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. Como esta es la primera unidad del curso, no hay preguntas sobre unidades anteriores; en su lugar, las tres primeras comprueban lo que el curso da por sabido: el cociente y el resto de una división entera, el orden de los pasos de un procedimiento y el nombre, la extensión y la carpeta de un archivo. Las siete siguientes tocan, en orden, las ideas centrales de las seis clases de la unidad. Quien nunca haya programado no debe esperar acertarlas, y no importa: 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 anterioresSe reparten 47 hojas entre 6 personas, en partes enteras iguales, y las que no alcanzan para una vuelta completa se guardan. ¿Cuántas recibe cada persona y cuántas se guardan?
Es la división con decimales, no la entera: las hojas no se parten, y la pregunta pide cuántas sobran.Redondear el cociente hacia arriba exige hojas que no hay; el resto de la división entera nunca es negativo cuando dividendo y divisor son positivos.Confunde el resto con la parte decimal del cociente: el resto se cuenta en hojas, no en fracciones de vuelta.Es la división entera: el cociente es el mayor número de vueltas completas, y el resto lo que sobra, que siempre es menor que el divisor. El curso la usa desde el primer programa, y en C++ tiene operadores propios.Repasar: Del problema al algoritmo
Pregunta 2De unidades anterioresPara enviar un archivo adjunto por correo electrónico hay cuatro pasos: A, escribir la dirección del destinatario; B, pulsar «Enviar»; C, abrir un mensaje nuevo; D, adjuntar el archivo. ¿Qué orden es el adecuado?
El orden de la enumeración no es el orden de la ejecución: con él, el mensaje se enviaría antes de existir.El resultado depende del orden: lo que se adjunta después de enviar no llega.Envía el mensaje sin destinatario y sin adjunto; los pasos posteriores ya no lo cambian.Algunos pasos dependen de otros (no se puede adjuntar a un mensaje que no se abrió, ni completar uno ya enviado), y otros no. Reconocer esas dependencias es lo primero que exige escribir un algoritmo.Repasar: Del problema al algoritmo
Pregunta 3De unidades anterioresUn archivo está guardado en
C:\Users\ana\programas\suma.cpp. ¿Cuál es su nombre, cuál su extensión y en qué carpeta está?Confunde la carpeta que contiene el archivo con el archivo mismo: el nombre es el último componente de la ruta.La extensión es parte del nombre; algunos sistemas la ocultan por omisión, y el curso pide mostrarla, porquesuma.cppysuma.exeson archivos muy distintos.C:es la unidad donde comienza la ruta, no una extensión.La ruta enumera las carpetas desde la raíz hasta el archivo; la extensión, lo que sigue al último punto del nombre, dice qué clase de contenido tiene:.cppes código fuente de C++. Para compilarlo, la terminal debe situarse en esa carpeta o recibir la ruta completa.Repasar: Compilar, ejecutar y configurar
Pregunta 4Una receta dice: «Si la masa está seca, añadir una cucharada de agua y amasar; repetir hasta que no lo esté». La masa necesita exactamente tres cucharadas para dejar de estar seca. ¿Cuántas veces se pregunta si la masa está seca?
No cuenta la pregunta cuya respuesta es «no», que también se hace: sin ella, nadie sabría que hay que dejar de añadir agua.Confunde el texto del procedimiento con su ejecución: la condición está escrita una vez, pero se evalúa en cada vuelta.Cuenta los intervalos entre las cucharadas, no las preguntas.En toda repetición que pregunta antes de actuar, la condición se evalúa una vez más que el cuerpo: la última pregunta es la que permite salir. Seguir el procedimiento a mano, contando, lo muestra sin ambigüedad.Repasar: Del problema al algoritmo
Pregunta 5¿Cuál de estas instrucciones puede seguirla cualquier persona, o una máquina, exactamente de la misma manera?
Depende del gusto de quien ejecuta: dos personas la seguirían de manera distinta, y una máquina no tiene gusto.No dice cuántas veces ni qué es quedar bien: la condición de término no es comprobable.No fija los números: «grande» no es una cantidad, y el divisor podría ser cero.Dice qué operación se hace, con qué dato y dónde queda el resultado; nada depende del juicio de quien la ejecuta. Esa precisión es una de las tres exigencias de un algoritmo.Repasar: Del problema al algoritmo
Pregunta 6Un programa se compila sin errores ni avisos, se ejecuta bien con muchos datos, y con uno en particular se detiene con el mensaje «division by zero». ¿En qué momento se produjo el error?
El compilador traduce el texto, no lo ejecuta, y no conoce los datos que el usuario escribirá.El enlazador reúne las partes del programa; no hace cuentas ni ve datos.Con otros datos el mismo ejecutable funciona: el defecto está en lo que el programa hace con ese dato, no en las herramientas.Lo que depende solo del texto del programa se descubre al compilar o al enlazar; lo que depende de los datos, solo al ejecutar. Por eso un programa que compila no está, por ello, libre de errores.Repasar: Programas, compiladores y C++
Pregunta 7Se instaló Visual Studio Code con su extensión de C++, y al pedir
g++ --versionen la terminal, esta responde que no reconoceg++. ¿Qué es lo más probable?La extensión no contiene el compilador ni interviene en lo que la terminal encuentra.La ordeng++ --versionno compila ningún programa: solo pregunta la versión, y la terminal ni siquiera encontró a quién preguntársela.El editor es indiferente: lo que falta es el compilador, en cualquier editor.El editor no compila: llama a un compilador aparte, que debe estar instalado y ser encontrado por la terminal. La extensión de C++ ayuda a escribir el código, pero no trae compilador.Pregunta 8El compilador escribe un mensaje que comienza con
warning:y, a pesar de él, produce el ejecutable. ¿Qué significa?Eso sería un error (error:), y entonces no habría ejecutable.Funcionar con los datos probados no prueba nada sobre los demás; un aviso ignorado es, a menudo, el error de mañana.El ejecutable es normal; lo dudoso es lo que el programa hace en el lugar señalado.Un error impide obtener el ejecutable; un aviso lo permite, pero señala código sospechoso. Muchos avisos delatan defectos reales, y por eso el curso exige programas que compilen sin ninguno.Repasar: Compilar, ejecutar y configurar
Pregunta 9¿Dónde comienza la ejecución de un programa de C++?
La primera línea suele ser una directiva#include, que se procesa antes de compilar y no se ejecuta.El orden en el archivo no decide el punto de entrada; lo decide el nombremain.La norma fija el nombre del punto de entrada; no se elige en la orden de compilación.maines el punto de entrada: el sistema la llama al poner en marcha el programa, y el programa termina cuando ella termina. Un programa sinmaincompila, pero no enlaza.Repasar: Anatomía de un programa
Pregunta 10Un programa declara
int age{};, ejecutastd::cin >> age;para leer una edad, y el usuario escribeabc. ¿Qué ocurre?No se detiene: continúa como si la lectura hubiera ido bien, y por eso el defecto es peligroso.Una variableintsolo guarda enteros; las letras no se convierten en número ni se guardan.La lectura no reintenta: fracasa una vez y deja el flujo en error.La lectura de un entero fracasa al encontrar una letra; la norma dice que la variable recibe 0 y que las lecturas siguientes no harán nada hasta que se trate el error. Si el programa no comprueba la lectura, escribe conclusiones falsas sin ninguna señal.Repasar: Entrada, salida y errores
Los contenidos de la unidad
La unidad tiene seis clases, que recorren en orden el camino de un problema a un programa en funcionamiento. Cada una supone la anterior, y la primera no supone nada del lenguaje.
- Del problema al algoritmo. El curso comienza sin código, porque el algoritmo precede al programa. La clase enseña a especificar un problema por su entrada, su salida y la relación entre ambas (la precondición y la poscondición); a describir un algoritmo en pasos numerados, sin ambigüedad; a seguirlo a mano con una tabla de traza; a reconocer en él la secuencia, la decisión y la repetición; y a justificar que una repetición termina, con una cantidad que decrece en cada vuelta.
- Programas, compiladores y C++. Un algoritmo escrito para una máquina es un programa, y un programa de C++ no se ejecuta tal como se escribe: el preprocesador, el compilador y el enlazador lo convierten en un ejecutable. La clase recorre esas tres etapas, distingue lo que se descubre al compilar de lo que solo se manifiesta al ejecutar, compara el modelo compilado con el interpretado y sitúa en el tiempo las normas del lenguaje, hasta C++23, la que el curso usa.
- Instalar el entorno en Windows, macOS y Linux. Tres guías completas, una por sistema, para instalar un compilador capaz de C++23 y el editor Visual Studio Code con su extensión de C++, comprobar que todo funciona con un programa de prueba y resolver las fallas frecuentes: el compilador que la terminal no encuentra, la versión antigua y la norma que no se pidió.
- Compilar, ejecutar y configurar. El ciclo de editar, guardar, compilar, ejecutar y leer, desde la terminal y desde el editor, con la orden de compilación del curso. La clase distingue los errores, que impiden el ejecutable, de los avisos, que señalan código sospechoso; activa los detectores, que vigilan el programa mientras corre; y explica por qué una salida muestra símbolos extraños en lugar de tildes y eñes.
- Anatomía de un programa. El programa mínimo, pieza por pieza: la directiva de inclusión y las cabeceras, la función
mainy el código de salida, el espacio de nombresstd, las sentencias, los bloques y los comentarios. La clase enseña a corregir los errores de estructura leyendo los mensajes del compilador desde el primero, y fija la guía de estilo del curso. - Entrada, salida y errores. El programa se comunica con el exterior: escribe con
std::printystd::println, con campos de formato para el ancho y los decimales, y lee constd::cin. La clase muestra qué ocurre cuando la entrada no tiene la forma esperada y cómo se comprueba la lectura, y cierra la unidad con la clasificación de los errores por su momento: de compilación, de enlace, de ejecución y de lógica.
El hilo que las une es el del propio programa. La primera clase lo concibe, la segunda explica en qué se convierte, la tercera instala las herramientas que lo convierten, la cuarta enseña a usarlas y a escuchar lo que dicen, la quinta lo disecciona y la sexta lo pone a conversar con quien lo usa. Si esto es así, al final de la unidad el estudiante sabe todavía muy poco de C++, pero sabe cómo se trabaja con él, y eso es lo que el resto del curso supone.
Lo que se da por sabido
El curso no supone ninguna experiencia previa en programación. Supone, en cambio, tres destrezas que conviene repasar ahora, si la evaluación de entrada mostró alguna duda.
La primera es la aritmética escolar: operar con enteros y con decimales, respetar el orden de las operaciones (la multiplicación y la división antes que la suma y la resta, salvo paréntesis) y, sobre todo, calcular el cociente y el resto de una división entera. Esta última es más importante de lo que parece. Dividir 47 hojas entre 6 personas da 7 a cada una y sobran 5, lo que se escribe , con el resto menor que el divisor . C++ tiene un operador para el cociente y otro para el resto, y una gran parte de los cálculos con enteros (convertir segundos en horas, separar las cifras de un número, decidir si un número es par) se reduce a ellos. Quien quiera estudiarla con detenimiento la encuentra, con su demostración, en el curso Álgebra y Geometría I: Números, Funciones y Geometría del Plano; aquí basta saber calcularla.
La segunda es la costumbre de seguir instrucciones escritas al pie de la letra y de reconocer cuándo una instrucción no basta para saber qué hacer. No se trata de un conocimiento, sino de una actitud: leer «añadir sal a gusto» y advertir que esa instrucción depende de quien la ejecuta. La primera clase de la unidad convierte esa actitud en método.
La tercera es el manejo básico de un computador: crear una carpeta, guardar en ella un archivo con un nombre elegido, reconocer la extensión del nombre (.cpp, .txt, .exe) y saber en qué carpeta está cada archivo. Conviene configurar desde ahora el sistema para que muestre las extensiones, que algunos sistemas, como Windows, ocultan por omisión: el código fuente suma.cpp y el ejecutable suma.exe son archivos muy distintos, y confundirlos es una fuente de errores absurdos. La unidad enseña también a usar la terminal, de modo que no hace falta saberlo de antemano; basta con estar dispuesto a escribir órdenes en lugar de pulsar botones. Instalar programas exige, por último, poder hacerlo en el propio computador; la clase de instalación indica una alternativa en línea para quien no pueda.
No se supone el inglés. Los mensajes del compilador están en inglés, y el curso enseña a leerlos campo por campo, de modo que lo que importa de ellos (el archivo, la línea, la clase de defecto) se entiende sin dominar la lengua. Tampoco se supone ninguna matemática más allá de la escolar: los ejemplos usan la división, los promedios, las tablas de multiplicar, las fechas y las horas.
El problema que la unidad resuelve
Un cálculo que se sabe hacer a mano no es todavía un programa. La distancia entre ambos es lo que la unidad enseña a recorrer, y un problema sencillo permite medirla.
Un cronómetro registra la duración de cada actividad como un número de segundos, por ejemplo 7384, y se quiere escribirla en la forma habitual de horas, minutos y segundos, con los minutos y los segundos siempre en dos cifras: 2:03:04. A mano, el cálculo es una cadena de divisiones: , de donde resultan 2 horas y 184 segundos; , de donde resultan 3 minutos y 4 segundos. Para una duración se hace en un minuto. Para las mil duraciones de un registro, en cambio, el cálculo a mano es largo y propenso a errores, y la tarea se presta a que una máquina la ejecute.
Ahora bien, una máquina no puede recibir la explicación anterior. Recibe un texto en un lenguaje de programación, y para escribir ese texto hay que haber resuelto antes tres cuestiones que el cálculo a mano dejaba implícitas. La primera es la especificación: qué entra (un número entero de segundos, no negativo), qué sale (tres enteros, las horas, los minutos y los segundos) y qué relación los une: si es el total, , con y . La segunda es el algoritmo: los pasos precisos que, para cualquier entrada admisible, producen esa salida.
- toma el valor del cociente de por .
- toma el valor del cociente por del resto de por .
- toma el valor del resto de por .
- Escribir , dos puntos, con dos cifras, dos puntos y con dos cifras.
La tercera es la escritura del algoritmo en C++, con la forma exacta que el lenguaje exige, y su traducción a un ejecutable con las herramientas adecuadas. El programa siguiente lo hace. Contiene muchas cosas que todavía no se han explicado: las variables (clase 2.1), los operadores / y %, que dan el cociente y el resto de la división entera (clase 3.1), la lectura con std::cin y los campos de formato como {:02}, que escribe un número con dos cifras completando con ceros (clase 1.6). Por ahora basta reconocer en él los cuatro pasos del algoritmo.
#include <iostream>#include <print>int main(){ int total{}; // las variables se explicarán en la clase 2.1 std::print("Duración en segundos: "); std::cin >> total; const int hours{total / 3600}; const int minutes{total % 3600 / 60}; const int seconds{total % 60}; std::println("{} s = {}:{:02}:{:02}", total, hours, minutes, seconds);}7384Duración en segundos: 7384 s = 2:03:04Las líneas 9 a 11 son los pasos 1 a 3, y la línea 12 es el paso 4. Que el resultado coincida con el calculado a mano no es una casualidad, sino la comprobación que todo programa merece: probarlo primero con un dato cuya respuesta se conoce.
El programa resuelve el problema, pero la unidad enseña también a desconfiar de él. Si el usuario escribe abc en lugar de un número, la lectura fracasa, total queda en cero y el programa escribe, sin ninguna señal de alarma, que la duración es 0:00:00: una conclusión falsa con apariencia de verdadera. Si escribe una duración negativa, la especificación no dice qué debe ocurrir, y el resultado carece de sentido. Si se escribe total / 360 en lugar de total / 3600, el programa compila, se ejecuta y da un resultado equivocado, y ninguna herramienta lo advierte. Cada uno de esos defectos pertenece a una clase distinta de error, que se descubre en un momento distinto y se busca de un modo distinto; la última clase de la unidad los clasifica. De ello se sigue que el problema que la unidad resuelve no es solo el de escribir este programa, sino el de saber por qué funciona, con qué datos deja de funcionar y qué herramienta avisará, o no, de cada defecto.
Por tanto, al terminar la unidad el estudiante podrá escribir, compilar y ejecutar programas de esta clase: unos pocos datos de entrada, unas cuentas en secuencia y unos resultados escritos con formato. No podrá todavía tomar decisiones ni repetir instrucciones en C++ (aunque sí en un algoritmo escrito en español), ni elegir con criterio el tipo de cada dato; eso es lo que traen las unidades siguientes.
Adónde conduce
La unidad es el umbral del curso. Lo que en ella se usa sin explicar se explica después, en este orden. La unidad 2, «Datos y tipos», explica las variables y cómo se guardan en la memoria, los límites de los enteros (y por qué un cálculo correcto puede desbordarse), el redondeo de los números con decimales y las conversiones entre tipos. La unidad 3, «Expresiones y operadores», explica la aritmética de C++, con el cociente y el resto de los negativos, la lógica de las condiciones y lo que la norma deja sin definir en una expresión. La unidad 4, «Control de flujo», lleva a C++ las decisiones y las repeticiones que la primera clase escribe en español, y enseña a justificar que un bucle es correcto y termina. La unidad 5 descompone los programas en funciones; la 6 introduce los datos compuestos (arreglos, vectores, tablas y registros), con los algoritmos de búsqueda y ordenación y su costo; la 7 trata el texto, la entrada robusta y los archivos; y la 8, los programas de varios archivos, las pruebas sistemáticas y el depurador.
Después del curso, Programación en C++ II continúa con lo que este deja fuera a propósito: los punteros y la memoria dinámica, las clases con métodos, las plantillas propias, las funciones anónimas y las excepciones. Ninguno de esos temas es necesario para resolver los problemas de este curso, y aplazarlos permite concentrarse en lo que vale en cualquier lenguaje: especificar, diseñar el algoritmo, escribirlo con claridad y comprobar que es correcto. La clase de síntesis de esta unidad recogerá precisamente esa distinción, entre lo que es propio de C++ y lo que se llevará a cualquier otro lenguaje.