Estructura de un programa, cout y tipos
Anatomía de un archivo .cpp, entrada y salida por consola, y los tipos fundamentales
Todo archivo .cpp tiene directivas, declaraciones y una función main. En esta lección recorres esa estructura, escribes y lees datos con std::cout y std::cin, eliges tipos fundamentales con criterio y das formato a los números de tus informes.
- Identificar las partes de un programa C++ y el papel de main
- Escribir por consola con std::cout y leer con std::cin y std::getline
- Elegir entre int, double, char, bool y std::string según el dato
- Comprobar el tamaño de un tipo con sizeof
- Formatear números reales con std::fixed y std::setprecision
Antes necesitas: ¿Qué es C++? Compilador y primer programa
En esta lección
- ¿Qué es la estructura de un programa?
- ¿Para qué sirve?
- ¿Cómo funciona por dentro?
- Sintaxis
- Ejemplo básico: presentar datos
- Ejemplo intermedio: dar formato a números
- Caso práctico: boleta con IGV
- Visualización: cómo se construye una línea de salida
- Leer datos con std::cin
- Errores comunes
- Buenas prácticas
- Ejercicios
- Soluciones explicadas
- Resumen
- Evaluación
Un programa en C++ no es una lista de órdenes sueltas: es un archivo con una estructura fija, un punto de entrada y declaraciones que el compilador debe resolver antes de ejecutar nada. En esta lección desarmas ese esqueleto y aprendes a mover datos hacia dentro y hacia fuera con std::cin y std::cout.
¿Qué es la estructura de un programa?
Llamamos estructura al orden y a las piezas mínimas que el compilador espera: directivas del preprocesador, declaraciones de tipos y funciones, y una función main. Todo lo demás son sentencias dentro de bloques.
Un tipo es un contrato: define cuántos bytes ocupa un valor, qué operaciones admite y cómo se interpreta esa memoria. int y double parecen intercambiables porque ambos guardan números, pero uno trunca los decimales y el otro los conserva.
- Directivas:
#includetrae declaraciones de la biblioteca y se procesa antes de compilar. - Función
main: única y obligatoria; el sistema operativo empieza ahí. - Sentencias: terminan en
;y viven dentro de un bloque entre llaves. - Declaraciones: introducen nombres con un tipo, como
int edad = 36;.
¿Para qué sirve?
Elegir bien la estructura y los tipos evita dos problemas: errores de compilación por declaraciones que faltan y errores silenciosos por tipos que no representan lo que crees.
- Herramientas de consola: leer líneas de un archivo o de la terminal y escribir resultados.
- Informes y registros: imprimir tablas alineadas y números con decimales fijos.
- Ciencia de datos: representar una columna con el tipo correcto antes de calcular.
- Machine Learning: guardar métricas (
double), conteos (int) y etiquetas (std::string).
Python resuelve parte de esto por ti: input() siempre devuelve texto y los enteros crecen solos. En C++ decides el tipo y pagas por las conversiones que necesites.
¿Cómo funciona por dentro?
std::cout y std::cin son objetos globales conectados a la salida y la entrada estándar. No son funciones: son flujos, y el operador << está sobrecargado para cada tipo. Cuando escribes std::cout << 42, el compilador elige la versión que convierte un int a texto.
Los flujos usan un búfer: los datos se acumulan y se vacían al llenarse, al cerrar el programa o al encontrar std::endl. Por eso '\n' es más barato que std::endl: no fuerza el vaciado.
El tamaño de cada tipo lo fija la implementación dentro de unos mínimos del estándar. sizeof te dice cuántos bytes ocupa un valor en tu máquina, y ese número cambia entre plataformas de 32 y 64 bits.
#include <iostream>
int main() {
std::cout << "int: " << sizeof(int) << " bytes\n";
std::cout << "double: " << sizeof(double) << " bytes\n";
std::cout << "float: " << sizeof(float) << " bytes\n";
std::cout << "char: " << sizeof(char) << " byte\n";
std::cout << "bool: " << sizeof(bool) << " byte\n";
std::cout << "long long: " << sizeof(long long) << " bytes\n";
return 0;
}En una máquina de 64 bits verás int 4, double 8, float 4, char 1, bool 1 y long long 8. Que bool ocupe un byte no significa que guarde 256 valores: solo representa true o false.
Sintaxis
La forma canónica de un programa que lee, calcula y escribe es esta:
#include <iostream>
#include <string>
int main() {
// declaraciones
// lectura con std::cin
// cálculo
// escritura con std::cout
return 0;
}Dentro de main, cada declaración sigue el patrón tipo nombre = valor;. std::cout << a << b encadena escrituras; std::cin >> a >> b encadena lecturas y separa por espacios.
#include <iostream>parastd::cout,std::cinystd::endl.#include <string>parastd::string; no lo heredes de otra cabecera.#include <iomanip>parastd::fixedystd::setprecision.std::delante de cada nombre de la biblioteca.return 0;al final demain.
Ejemplo básico: presentar datos
Tres variables, tres tipos y tres líneas de salida. Observa que std::cout convierte solo: no hay que llamar a str() como en Python.
#include <iostream>
#include <string>
int main() {
std::string nombre = "Ada";
int edad = 36;
double estatura = 1.68;
std::cout << "Nombre: " << nombre << '\n';
std::cout << "Edad: " << edad << " años\n";
std::cout << "Estatura: " << estatura << " m\n";
return 0;
}std::string guarda texto de longitud variable y reserva memoria por su cuenta; int guarda enteros sin decimales; double guarda reales con precisión doble. En la salida, << inserta cada valor en el flujo y '\n' cierra la línea. estatura aparece como 1.68 porque el flujo elige la representación más corta que reconstruye el valor.
Ejemplo intermedio: dar formato a números
Los reales sin formato son incómodos en un informe: 19.9 tiene un decimal y 3.582 tres. Los manipuladores de <iomanip> cambian cómo escribe el flujo, y el cambio es persistente: afecta a todo lo que se imprima después.
#include <iomanip>
#include <iostream>
int main() {
double precio = 19.9;
std::cout << "Sin formato: " << precio << '\n';
std::cout << std::fixed << std::setprecision(2);
std::cout << "Con formato: " << precio << '\n';
std::cout << "IGV (18 %): " << precio * 0.18 << '\n';
return 0;
}std::fixed fija la notación decimal, sin exponente. std::setprecision(2) indica dos dígitos después del punto cuando fixed está activo. El IGV se calcula con precio * 0.18 y se muestra redondeado, aunque el valor interno conserve más precisión.
El orden importa: si imprimes antes de aplicar fixed, esa primera línea sale sin formato. Los manipuladores no son parte de la cadena, son cambios de estado del flujo.
Caso práctico: boleta con IGV
Una tienda necesita una boleta con subtotal, impuesto y total. El cálculo es simple, pero mezcla un int (cantidad) con double (precio), y ahí aparecen los errores de tipo si no eliges bien.
#include <iomanip>
#include <iostream>
#include <string>
int main() {
std::string producto = "Café 250 g";
int cantidad = 3;
double precio = 12.5;
constexpr double igv = 0.18;
double subtotal = cantidad * precio;
double impuesto = subtotal * igv;
double total = subtotal + impuesto;
std::cout << std::fixed << std::setprecision(2);
std::cout << "Producto: " << producto << '\n';
std::cout << "Subtotal: S/ " << subtotal << '\n';
std::cout << "IGV: S/ " << impuesto << '\n';
std::cout << "Total: S/ " << total << '\n';
return 0;
}Verifica las cifras: 3 × 12.50 = 37.50; el 18 % es 6.75; el total, 44.25. constexpr double igv deja claro que la tasa no cambia. cantidad * precio convierte el int a double de forma automática, porque la multiplicación entre enteros y reales se hace en real.
Si escribieras cantidad * 12.5, funcionaría igual, pero el 12.5 suelto es un número mágico: quien lea el código no sabe de dónde sale.
Visualización: cómo se construye una línea de salida
La traza muestra el estado después de cada declaración y el momento exacto en que aparece la salida. Fíjate en que la línea 8 produce todo el texto de una vez, aunque concatene cuatro valores.
#include <iostream>#include <string>int main() { std::string curso = "C++"; int semana = 2; double horas = 6.5; std::cout << curso << ": " << horas << " h en la semana " << semana << '\n'; return 0;}main. Todavía no hay variables locales.Sin variables en este paso.
—
Avanza paso a paso: observa la línea resaltada, las variables y la salida.
Leer datos con std::cin
std::cin >> variable lee un valor y lo convierte al tipo del destino. El operador salta los espacios iniciales y se detiene en el siguiente espacio: para un std::string, eso significa una palabra, no una frase.
#include <iostream>
#include <string>
int main() {
std::string nombre;
int edad = 0;
std::cout << "¿Cómo te llamas? ";
std::cin >> nombre;
std::cout << "¿Cuántos años tienes? ";
std::cin >> edad;
std::cout << "Hola, " << nombre << ". Tienes " << edad << " años.\n";
return 0;
}Prueba con Ada Lovelace como nombre: el programa se queda con Ada y deja Lovelace en el búfer. Para leer una línea completa se usa std::getline(std::cin, nombre), que consume hasta el salto de línea. No mezcles ambos sin cuidado: un >> deja el salto pendiente y el siguiente getline lee una cadena vacía.
Errores comunes
| Mensaje | Causa | Solución |
|---|---|---|
unknown type name 'string' | Falta #include <string> o el prefijo std:: | Incluye la cabecera y escribe std::string |
use of undeclared identifier 'cout' | Falta #include <iostream> o std:: | Añade la cabecera y el prefijo |
no matching function for call to 'getline' | Llamaste getline sin std:: | Escribe std::getline(std::cin, texto) |
expected ';' before ... | Olvidaste el punto y coma anterior | Revísalo: el error se reporta en la línea siguiente |
La salida muestra 3 y esperabas 3.5 | Dividiste dos int | Convierte uno a double antes de dividir |
El último caso no es un error de compilación: el programa compila y hace exactamente lo que le pediste. Por eso los errores silenciosos de tipo son más peligrosos que los que el compilador detecta.
#include <iostream>
int main() {
string nombre = "Ada";
cout << nombre << '\n';
return 0;
}#include <iostream>
#include <string>
int main() {
std::string nombre = "Ada";
std::cout << nombre << '\n';
return 0;
}Sin `using namespace std;` —y en este curso no lo usamos— cada nombre de la biblioteca necesita su prefijo. El compilador incluso te sugiere `std::string` y `std::cout` en el mensaje.
Buenas prácticas
- Incluye solo lo que usas:
<iostream>,<string>e<iomanip>cuando hacen falta. - Nunca escribas
using namespace std;: contamina el espacio global y crea ambigüedades. - Prefiere
'\n'astd::endlsalvo que necesites vaciar el búfer en ese punto. - Declara las variables cerca de su primer uso y con un valor inicial.
- Usa
std::stringpara texto; los arrays decharquedan para interoperar con APIs de C. - Comprueba la salida con números pequeños a mano antes de confiar en el formato.
Ejercicios
Ficha por teclado
std::getline para los textos y std::cin >> para el ciclo. Prueba con un nombre compuesto, como Ada Lovelace, para comprobar que no se corta.Pista
std::getline necesita <string> y dos argumentos: el flujo y la variable. El ciclo es un entero, así que >> es suficiente.
Conversor de temperatura
double y muestra su equivalente en Fahrenheit con un decimal. La fórmula es F = C * 9 / 5 + 32. Comprueba con 0 → 32.0, 100 → 212.0 y -40 → -40.0.Pista
Usa 9.0 / 5.0 o 9.0 / 5; si divides enteros, pierdes la parte decimal.
#include #include <string> int main() { std::string lenguaje = "C++"; std:: << "Aprendo " << lenguaje << '\n'; return ; }
La cabecera de entrada y salida declara `std::cout`; el retorno de `main` indica éxito.
Soluciones explicadas
En la ficha, el orden de las lecturas importa: getline consume el salto de línea completo, mientras que >> lo deja pendiente. Si después de std::cin >> ciclo llamaras a getline, obtendrías una cadena vacía; por eso el ciclo se lee al final, cuando ya no quedan textos pendientes.
En el conversor, la trampa está en la aritmética entera. celsius * 9 / 5 se evalúa de izquierda a derecha: celsius es double, así que toda la cadena es real y el resultado correcto sale sin trucos. Si celsius fuera int, habría que convertir antes de dividir.
El ejercicio de completar refuerza la dependencia entre cabecera, nombre cualificado y valor de retorno: las tres piezas tienen que coincidir para que el programa compile y termine con éxito.
Resumen
- Todo programa tiene directivas, declaraciones y una función
main. #includetrae declaraciones; sin la cabecera correcta, el tipo o el flujo no existen.std::cout <<escribe y convierte cada tipo a texto;std::cin >>lee una palabra o un número.std::getlinelee una línea completa y conviene para nombres con espacios.sizeofrevela el tamaño real de un tipo en tu plataforma.std::fixedystd::setprecision(n)controlan los decimales de los reales.- Los nombres de la biblioteca estándar viven en
std; escribe el prefijo.
Evaluación
¿Cuántos bytes ocupa un char según el estándar de C++?
Si el usuario escribe Ada Lovelace y lees con std::cin >> nombre, ¿qué queda en nombre?
¿Qué imprime std::cout << std::fixed << std::setprecision(3) << 2.5;?
¿Ya lo entendiste?
Márcala como completada para llevar tu progreso y desbloquear el siguiente paso de la ruta.