AulaML Python · C++
C++ principiante · 35 min · Fundamentos de C++

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.

Lección 2 de 3 del módulo
Al terminar esta lección podrás
  • 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
  1. ¿Qué es la estructura de un programa?
  2. ¿Para qué sirve?
  3. ¿Cómo funciona por dentro?
  4. Sintaxis
  5. Ejemplo básico: presentar datos
  6. Ejemplo intermedio: dar formato a números
  7. Caso práctico: boleta con IGV
  8. Visualización: cómo se construye una línea de salida
  9. Leer datos con std::cin
  10. Errores comunes
  11. Buenas prácticas
  12. Ejercicios
  13. Soluciones explicadas
  14. Resumen
  15. 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: #include trae 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.

CPP tamanos.cpp
#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:

CPP esqueleto.cpp
#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> para std::cout, std::cin y std::endl.
  • #include <string> para std::string; no lo heredes de otra cabecera.
  • #include <iomanip> para std::fixed y std::setprecision.
  • std:: delante de cada nombre de la biblioteca.
  • return 0; al final de main.

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.

CPP presentar.cpp
#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.

CPP formato.cpp
#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.

CPP boleta.cpp
#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.

Ejecución visual ·Estado de las variables y salida
1 / 6
1 #include <iostream>
2 #include <string>
3
4 int main() {
5 std::string curso = "C++";
6 int semana = 2;
7 double horas = 6.5;
8 std::cout << curso << ": " << horas << " h en la semana " << semana << '\n';
9 return 0;
10 }
El sistema operativo entra en main. Todavía no hay variables locales.
Variables

Sin variables en este paso.

Salida
—

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.

CPP leer.cpp
#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

MensajeCausaSolució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 anteriorRevísalo: el error se reporta en la línea siguiente
La salida muestra 3 y esperabas 3.5Dividiste dos intConvierte 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.

El espacio de nombres no es opcional
Incorrecto
PYTHON No compila
#include <iostream>

int main() {
    string nombre = "Ada";
    cout << nombre << '\n';
    return 0;
}
Correcto
PYTHON Correcto
#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' a std::endl salvo que necesites vaciar el búfer en ese punto.
  • Declara las variables cerca de su primer uso y con un valor inicial.
  • Usa std::string para texto; los arrays de char quedan para interoperar con APIs de C.
  • Comprueba la salida con números pequeños a mano antes de confiar en el formato.

Ejercicios

Ejercicio 1

Ficha por teclado

Escribe un programa que pida nombre completo, carrera y ciclo, y muestre una ficha de tres líneas. Usa 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.

Ejercicio 2

Conversor de temperatura

Pide una temperatura en grados Celsius como 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.

Completar código Completa el programa
#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.
  • #include trae 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::getline lee una línea completa y conviene para nombres con espacios.
  • sizeof revela el tamaño real de un tipo en tu plataforma.
  • std::fixed y std::setprecision(n) controlan los decimales de los reales.
  • Los nombres de la biblioteca estándar viven en std; escribe el prefijo.

Evaluación

Evaluación 1

¿Cuántos bytes ocupa un char según el estándar de C++?

Evaluación 2

Si el usuario escribe Ada Lovelace y lees con std::cin >> nombre, ¿qué queda en nombre?

Evaluación 3

¿Qué imprime std::cout << std::fixed << std::setprecision(3) << 2.5;?

Tus notas

¿Ya lo entendiste?

Márcala como completada para llevar tu progreso y desbloquear el siguiente paso de la ruta.