Inicio
Inicio
1. Conceptos Básicos
a. Variables
Definición: Una variable es un espacio en la memoria (ram) que se utiliza para almacenar un valor
que puede cambiar durante la ejecución de un programa.
Declaración: Para declarar una variable, debes especificar el tipo de dato seguido del nombre de
la variable. Ejemplo:
int edad;
double salario;
char inicial;
Asignación: Después de declarar una variable, puedes asignarle un valor usando el operador =
edad = 25;
salario = 1500.75;
inicial = 'A';
#include <iostream>
using namespace std;
void miFuncion() {
int numero = 10; // Variable local de miFuncion
cout << "El número es: " << numero << endl;
}
int main() {
miFuncion();
// cout << numero; // Error: 'numero' no está definido en main
return 0;
}
En este ejemplo, la variable numero es local a miFuncion y no puede ser accedida desde main.
#include <iostream>
using namespace std;
void miFuncion() {
cout << "Variable global dentro de miFuncion: " << numero << endl;
}
int main() {
cout << "Variable global en main: " << numero << endl;
miFuncion();
return 0;
}
En este ejemplo, la variable numero es global y puede ser utilizada tanto en main como en
miFuncion.
#include <iostream>
using namespace std;
void sumar() {
int a = 5, b = 10; // Variables locales
int resultado = a + b;
cout << "El resultado de la suma es: " << resultado << endl;
}
int main() {
sumar();
return 0;
}
Variables globales: Cuándo y cómo usarlas Las variables globales se usan cuando necesitas
compartir un dato entre varias funciones.
Sin embargo, su uso debe ser limitado porque:
Pueden ser modificadas por cualquier función, lo que puede llevar a errores difíciles de detectar.
Reducen la modularidad del programa.
Ejemplo: Usar una variable global para contar acciones:
#include <iostream>
using namespace std;
int contador = 0; // Variable global
void incrementar() { contador++; // Modifica la variable global }
int main() {
incrementar();
incrementar();
cout << "El contador es: " << contador << endl; // Imprime: 2
return 0;
}
5. Buenas prácticas
Usa variables locales siempre que sea posible:
#include <iostream>
using namespace std;
void miFuncion() {
int numero = 200; // Variable local que oculta la global
cout << "Variable local: " << numero << endl;
}
int main() {
cout << "Variable global: " << numero << endl;
miFuncion();
return 0;
}
Salida:
#include <iostream>
using namespace std;
void miFuncion() {
int numero = 20; // Variable local
cout << "Variable local: " << numero << endl;
cout << "Variable global usando '::': " << ::numero << endl;
}
int main() {
miFuncion();
return 0;
}
Salida:
Variable local: 20
Variable global usando '::': 50
Conversión de Variables a Constante:
En C++, puedes convertir una variable en una constante de diferentes maneras dependiendo de tu
propósito y del momento en que quieras garantizar que su valor no pueda cambiar. Aquí están las
formas más comunes de hacerlo:
1. Usar la palabra clave const
La forma más común de declarar una constante es usar const al declarar una variable. Una vez
asignado un valor, no puede modificarse.
• Características:
• El valor debe asignarse al momento de la declaración.
• Intentar modificarlo provocará un error en tiempo de compilación.
Ejemplo:
#include <iostream>
int main() {
const double pi = 3.14159; // Constante de tipo double
// pi = 3.14; // Error: no se puede modificar una constante
std::cout << "El valor de pi es: " << pi << std::endl;
return 0;
}
constexpr es una forma más estricta de definir constantes. Garantiza que el valor de la
constante sea evaluado en tiempo de compilación.
constexpr int valor = 100;
• Características:
• Ideal para constantes que necesitas evaluar durante la compilación.
• Solo se pueden asignar valores que también sean constantes en tiempo de compilación.
• Es más eficiente, especialmente cuando se usa en expresiones complejas.
Ejemplo:
#include <iostream>
constexpr int cuadrado(int x) { return x * x; }
int main() {
constexpr int valor = cuadrado(5); // Evaluado en tiempo de compilación
std::cout << "El cuadrado de 5 es: " << valor << std::endl;
return 0;
}
Otra manera de definir constantes es usar directivas del preprocesador con #define. Aunque es
una técnica válida, es menos recomendada en comparación con const y constexpr.
#define VALOR 42
• Características:
• No tiene tipo, por lo que no se verifica en tiempo de compilación.
• Puede causar problemas de depuración y errores difíciles de rastrear.
• No respeta el alcance (scope) como las constantes definidas con const o constexpr.
Ejemplo:
#include <iostream>
#define PI 3.14159
int main() {
std::cout << "El valor de PI es: " << PI << std::endl;
return 0;
}
enum se puede usar para definir constantes enteras relacionadas. Aunque no es su propósito
principal, es una técnica válida.
enum { CONSTANTE = 10 };
• Características:
• Útil para valores relacionados (como días de la semana, estados, etc.).
• Todas las constantes declaradas en el enum son de tipo int.
Ejemplo:
#include <iostream>
int main() {
enum { MAX_LIMITE = 100 };
std::cout << "El límite máximo es: " << MAX_LIMITE << std::endl;
return 0;
}
Puedes definir constantes como miembros de una clase o estructura. Para esto, puedes usar static
const o static constexpr.
int main() {
std::cout << "Constante en clase: " << MiClase::constante << std::endl;
return 0;
}
int main() {
std::cout << "El valor de pi es: " << MiClase::pi << std::endl;
return 0;
}
El uso (o NO) de Variables:
En C++, el atributo [[maybe_unused]] se introdujo en C++17 para indicar que una variable, función,
parámetro, o cualquier otra entidad del programa, puede no ser utilizada en algunas
circunstancias, y esto es intencional. Esto es útil porque, sin este atributo, los compiladores
suelen emitir advertencias sobre variables o funciones declaradas pero no utilizadas, lo que a
veces es necesario o deseado en ciertos contextos.
Sintaxis
O también:
#include <iostream>
int main() {
[[maybe_unused]] int x = 42; // 'x' no se utiliza, pero no genera advertencia
return 0;
}
En este caso, x no se utiliza dentro del programa. Si no se hubiera marcado con [[maybe_unused]],
el compilador podría emitir una advertencia. Pero con el atributo, le indicamos al compilador que
no emita advertencias porque es intencional.
#include <iostream>
int main() {
std::cout << "Programa principal" << std::endl;
return 0;
}
Aquí, la función funcionNoUsada no se utiliza en ninguna parte del programa, pero el atributo
[[maybe_unused]] evita que el compilador genere una advertencia.
La memoria RAM
La memoria RAM no necesariamente separa físicamente los datos según su tipo (como int,
double, float, etc.), pero sí tiene un orden lógico que los programas siguen para
organizarlos. A continuación, te lo explico paso a paso:
Datos inicializados: Variables globales o estáticas con un valor inicial definido, como
int x = 10;.
Heap (Montículo):
Es usado para datos dinámicos, es decir, memoria asignada manualmente con new en C++ o
funciones similares.
Ejemplo: int* ptr = new int[10];.
Stack (Pila):
Tamaño del dato y alineación: Cada tipo de dato ocupa un número específico de bytes y se
almacena de manera alineada. Por ejemplo:
int (generalmente 4 bytes) puede empezar en una dirección divisible por 4.
double (8 bytes) puede necesitar alineación a 8 bytes.
En este caso:
La reserva de memoria
depende del tipo de variable que declares y del alcance de la misma. Vamos a analizarlo
según el caso:
Ejemplo:
Estas variables existen durante toda la ejecución del programa, ya que se colocan en la
sección de datos estáticos de la memoria.
Ejemplo:
void ejemplo() {
int valor1; // Se reserva espacio en el stack al entrar a la función.
float valor2; // También en el stack.
} // La memoria se libera al salir de la función.
Ejemplo:
int valor1;
float valor2;
... como variables globales o estáticas, la memoria se reserva con la compilación, porque
estas variables se guardan en la sección de datos del programa.
void ejemplo() {
int valor1;
float valor2;
}
... la memoria no se reserva con la compilación, sino en tiempo de ejecución cuando la
función es llamada. Esto ocurre porque las variables locales viven en el stack y solo
existen durante la ejecución de la función.
Nota:
Cuando declaras un int valor (que ocupa 32 bits o 4 bytes) y le asignas un valor como 3,
efectivamente no estás utilizando todos los bits disponibles para ese tipo de dato. Sin
embargo, esto no se considera necesariamente un desperdicio, y a continuación te explico
por qué:
El uso de tipos de tamaño fijo como int permite que las operaciones aritméticas,
comparaciones y transferencias de datos se realicen de manera uniforme y eficiente.
El costo de usar un poco más de memoria para cada variable es insignificante en
comparación con los beneficios de rendimiento en sistemas modernos con suficiente RAM.
Sin embargo, si trabajas en un entorno donde la memoria es limitada (como sistemas
embebidos), puedes optar por tipos más pequeños, como:
Ejemplo:
#include <cstdint>
int8_t pequeño = 3; // Solo usa 8 bits.
NOTA: Dentro de #include <cstdint>, encontrarás tipos de enteros con tamaños fijos como:
int8_t y uint8_t para enteros de 8 bits con y sin signo, respectivamente.
Usa tipos de datos más pequeños (int8_t, uint8_t, etc.) en lugar de int si sabes que no
necesitas valores grandes.
struct Compacto {
int8_t a; // 1 byte
int8_t b; // 1 byte
}; // Total: 2 bytes en lugar de 8 si fueran ints normales.
struct Flags {
unsigned int flag1 : 1; // Solo 1 bit
unsigned int flag2 : 1; // Solo 1 bit
}; // Total: 2 bits en lugar de 2 bytes.
5. Caso práctico
Supongamos que necesitas almacenar solo números pequeños (como en un contador de 0 a
255):
Tiempo de Ejecución
El tiempo de ejecución, o "runtime" en inglés, se refiere al período durante el cual un
programa de computadora está siendo ejecutado. En otras palabras, es el tiempo desde que
el programa comienza a ejecutarse hasta que termina. Aquí hay algunos puntos clave sobre
el tiempo de ejecución:
Conceptos Clave:
Inicio del Programa: El tiempo de ejecución comienza cuando el programa es lanzado. Esto
puede ser al hacer clic en un icono, ejecutar un comando en la terminal, etc.
Gestión de Recursos: El sistema operativo asigna recursos como memoria, tiempo de CPU y
acceso a dispositivos de entrada/salida al programa durante su tiempo de ejecución.
Errores en Tiempo de Ejecución: Son problemas que ocurren mientras el programa está en
funcionamiento, como intentos de dividir por cero, acceso a memoria no válida, etc.
Estos errores suelen detener la ejecución del programa y pueden requerir depuración para
solucionarlos.
Ejemplo:
Imagina que tienes un programa en C++ que calcula la suma de dos números. El tiempo de
ejecución es el período en que el programa está recibiendo los números, sumándolos y
mostrando el resultado.
#include <iostream>
using namespace std;
int main() {
int a, b;
cout << "Ingrese dos números: ";
cin >> a >> b;
int suma = a + b;
cout << "La suma es: " << suma << endl;
return 0;
}
En este ejemplo:
Ejecución de instrucciones: Cuando el programa recibe los números, los suma y muestra el
resultado.
Fin del tiempo de ejecución: Cuando el programa termina y devuelve el control al sistema
operativo.
Tiempo de Compilación
El tiempo de compilación, o "compilation time" en inglés, es el período durante el cual
el código fuente de un programa se traduce a código máquina o código ejecutable por un
compilador. Este proceso ocurre antes de que el programa pueda ser ejecutado en una
computadora. Aquí tienes algunos puntos clave sobre el tiempo de compilación:
Conceptos Clave:
Traducción del código: Durante el tiempo de compilación, el compilador toma el código
fuente escrito en un lenguaje de alto nivel (como C++, Java, etc.) y lo convierte en
código máquina que puede ser entendido y ejecutado por la CPU.
Ejemplo en C++:
Supongamos que tienes el siguiente código fuente en C++:
#include <iostream>
using namespace std;
int main() {
cout << "Hola, mundo!" << endl;
return 0;
}
Proceso de Compilación:
Escribiendo el código fuente: Escribes el código en un archivo, por ejemplo,
holamundo.cpp.
./holamundo
Esto inicia el tiempo de ejecución, durante el cual el programa imprime "Hola, mundo!"
en la pantalla.
¿Qué es el operador ternario?
El operador ternario tiene la forma:
Componentes:
condición: Es una expresión booleana (que se evalúa como true o false).
?: Indica el inicio del operador ternario.
expresión1: Valor que se devuelve o ejecuta si la condición es true.
: → Separa las dos expresiones.
expresión2: Valor que se devuelve o ejecuta si la condición es false.
¿Cómo funciona?
El operador ternario evalúa la condición:
Ejemplo básico
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 20;
int mayor;
if (a > b) {
mayor = a;
} else {
mayor = b;
}
cout << "El número mayor es: " << mayor << endl;
return 0;
}
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 20;
cout << "El número mayor es: " << mayor << endl;
return 0;
}
#include <iostream>
#include <string>
using namespace std;
int main() {
int edad;
cout << "Ingresa tu edad: ";
cin >> edad;
return 0;
}
Eres: Adulto
Salida 2 (si ingresas 15):
Eres: Menor
#include <iostream>
using namespace std;
void mensajePositivo() {
cout << "El número es positivo." << endl;
}
void mensajeNegativo() {
cout << "El número es negativo o cero." << endl;
}
int main() {
int num;
cout << "Ingresa un número: ";
cin >> num;
return 0;
}
El número es positivo.
Salida 2 (si ingresas -3):
if (a > b) {
if (b > c) {
resultado = b;
} else {
resultado = c;
}
} else {
resultado = a;
}
Resumen
El operador ternario es una forma abreviada de escribir condiciones simples.
Sintaxis: condición ? expresión1 : expresión2.
Útil para asignaciones rápidas o llamadas simples a funciones.
Evítalo en condiciones complejas para no afectar la legibilidad.
b. Tipos de Datos:
Datos primitivos: Datos no primitivos
• char: Almacena un solo carácter (Ej. char • Arreglos (Arrays): Colección de elementos
letra = 'A';).Tamaño 1 byte; del mismo tipo.
• wchar_t 2 o 4 bytes Representa un carácter • Estructuras (Structs): Agrupación de
ancho (wide character) variables bajo un mismo nombre.
• int: Almacena números enteros (Ej. int x • Clases (Classes): Blueprint para crear
= 5;).Tamaño 4 byte; objetos con atributos y métodos.
• long: Para números más grandes. Tamaño 4 • Cadenas de caracteres (Strings): En C++
bytes (32-bit) o 8 bytes (64-bit). se puede usar std::string.
• Contenedores de la STL (Standard Template
• long long 8 bytes Entero muy
Library): Incluyen vectores, listas,
largo.
mapas, etc.
• float: Almacena números en coma flotante • Apuntadores (Pointers): Variables que
de precisión simple (Ej. float x = almacenan direcciones de memoria.
5.75f;).Tamaño 4 byte; • Enumeraciones (Enums): Conjunto de
• double: Almacena números en coma flotante constantes con nombre.
de doble precisión (Ej. double x =
19.99;). Tamaño 1 byte.
• long double 8, 12 o 16 bytes Número de
punto flotante de precisión extendida
(dependiendo del compilador).
• unsigned int: Solo números positivos
• bool: Almacena valores booleanos (true o
false). Tamaño 1 byte;
• char16_t y char32_t son tipos de datos
primitivos en C++. Fueron introducidos en
el estándar C++11 para proporcionar
soporte para caracteres de 16 y 32 bits,
respectivamente.
• char16_t se utiliza para representar
caracteres en codificación UTF-16.
• char32_t se utiliza para representar
caracteres en codificación UTF-32.
1. Incremento (++)
Este operador suma 1 al valor de la variable. Puede usarse de dos formas:
Ejemplo: Incremento
#include <iostream>
using namespace std;
int main() {
int x = 5;
// Incremento en prefijo
cout << "Prefijo (++x): " << ++x << endl; // Incrementa y luego muestra
// Incremento en postfijo
cout << "Postfijo (x++): " << x++ << endl; // Muestra y luego incrementa
cout << "Valor de x después del postfijo: " << x << endl;
return 0;
}
Salida:
Valor inicial de x: 5
Prefijo (++x): 6
Postfijo (x++): 6
Valor de x después del postfijo: 7
2. Decremento (--)
Este operador resta 1 al valor de la variable. También tiene dos formas:
Ejemplo: Decremento
#include <iostream>
using namespace std;
int main() {
int y = 10;
// Decremento en prefijo
cout << "Prefijo (--y): " << --y << endl; // Decrementa y luego muestra
// Decremento en postfijo
cout << "Postfijo (y--): " << y-- << endl; // Muestra y luego decrementa
cout << "Valor de y después del postfijo: " << y << endl;
return 0;
}
Salida:
Valor inicial de y: 10
Prefijo (--y): 9
Postfijo (y--): 9
Valor de y después del postfijo: 8
#include <iostream>
using namespace std;
int main() {
int a = 3, b = 3;
cout << "Resultado Prefijo (++a * 2): " << resultadoPrefijo << endl; // 8
cout << "Resultado Postfijo (b++ * 2): " << resultadoPostfijo << endl; // 6
return 0;
}
Operadores Lógicos
Los operadores lógicos son usados para evaluar expresiones lógicas y combinarlas.
Devuelven valores booleanos (true o false).
Ejemplo:
#include <iostream>
using namespace std;
int main() {
int x = 5, y = 10;
return 0;
}
Salida:
2. OR Lógico (||)
Este operador devuelve true si al menos una de las expresiones es verdadera.
Ejemplo:
#include <iostream>
using namespace std;
int main() {
int x = -5, y = 10;
if (x > 0 || y > 0) {
cout << "Al menos uno de los números es positivo" << endl;
} else {
cout << "Ningún número es positivo" << endl;
}
return 0;
}
Salida:
Ejemplo:
#include <iostream>
using namespace std;
int main() {
bool esVerdad = true;
return 0;
}
Salida:
Valor original: 1
Valor invertido: 0
Ejemplo:
#include <iostream>
using namespace std;
int main() {
int x = 5, y = 10, z = -3;
return 0;
}
Resumen
➢ Incremento y Decremento (++, --):
➢ Incrementan o decrementan en 1.
➢ Prefijo modifica antes, postfijo después.
➢ Operadores Lógicos (&&, ||, !):
➢ Usados para evaluar y combinar expresiones lógicas.
➢ Devuelven valores booleanos (true o false).
#include <iostream>
int main() {
int x = 10; // Asigna 10 a x
std::cout << "x = " << x << std::endl;
return 0;
}
#include <iostream>
int main() {
int x = 10;
x += 5; // Equivalente a: x = x + 5
std::cout << "x = " << x << std::endl; // Resultado: 15
return 0;
}
#include <iostream>
int main() {
int x = 20;
x -= 5; // Equivalente a: x = x - 5
std::cout << "x = " << x << std::endl; // Resultado: 15
return 0;
}
#include <iostream>
int main() {
int x = 4;
x *= 3; // Equivalente a: x = x * 3
std::cout << "x = " << x << std::endl; // Resultado: 12
return 0;
}
#include <iostream>
int main() {
int x = 20;
x /= 4; // Equivalente a: x = x / 4
std::cout << "x = " << x << std::endl; // Resultado: 5
return 0;
}
#include <iostream>
int main() {
int x = 23;
x %= 5; // Equivalente a: x = x % 5
std::cout << "x = " << x << std::endl; // Resultado: 3
return 0;
}
#include <iostream>
int main() {
int x = 5; // Binario: 0101
x <<= 1; // Equivalente a: x = x << 1 (Desplaza un bit a la izquierda)
std::cout << "x = " << x << std::endl; // Resultado: 10 (Binario: 1010)
return 0;
}
#include <iostream>
int main() {
int x = 20; // Binario: 10100
x >>= 2; // Equivalente a: x = x >> 2 (Desplaza dos bits a la derecha)
std::cout << "x = " << x << std::endl; // Resultado: 5 (Binario: 0101)
return 0;
}
#include <iostream>
int main() {
int x = 6; // Binario: 0110
x &= 3; // Equivalente a: x = x & 3 (Binario: 0011)
std::cout << "x = " << x << std::endl; // Resultado: 2 (Binario: 0010)
return 0;
}
int main() {
int x = 6; // Binario: 0110
x |= 3; // Equivalente a: x = x | 3 (Binario: 0011)
std::cout << "x = " << x << std::endl; // Resultado: 7 (Binario: 0111)
return 0;
}
11. Asignación con XOR bit a bit (^=)
Realiza una operación XOR bit a bit entre la variable de la izquierda y el valor de la derecha.
#include <iostream>
int main() {
int x = 6; // Binario: 0110
x ^= 3; // Equivalente a: x = x ^ 3 (Binario: 0011)
std::cout << "x = " << x << std::endl; // Resultado: 5 (Binario: 0101)
return 0;
}
Detalles Importantes:
\\: Se utiliza para imprimir la barra invertida en pantalla, ya que la barra invertida por sí sola
tiene un significado especial como carácter de escape.
\' y \": Son útiles para incluir comillas dentro de cadenas. Por ejemplo:
'\a': Puede no funcionar en todos los sistemas, dependiendo del soporte para sonidos de alerta.
'\r': Es menos común en C++, pero mueve el cursor al inicio de la línea actual, sobrescribiendo lo
que estaba previamente.
Ejemplo Práctico
#include <iostream>
int main() {
std::cout << "Hola\nMundo\n"; // Salto de línea
std::cout << "Hola\tMundo\n"; // Tabulación
std::cout << "Hola\\Mundo\n"; // Barra invertida
std::cout << "Hola\"Mundo\"\n"; // Comillas dobles
std::cout << "Hola\bMundo\n"; // Retroceso (Borra 'a')
return 0;
}
1. Librería necesaria:
Para funciones relacionadas con el tipo char y cadenas de caracteres, puedes utilizar
principalmente la librería:
Notas Importantes
Tipo de argumento: Todas estas funciones reciben un único carácter de tipo int. Es común pasar
valores char, ya que se convierten implícitamente a int.
Rango válido:
Los caracteres pasados deben estar en el rango representado por un unsigned char o el valor
especial EOF.-(end of file)
Si se pasa un valor fuera de este rango, el comportamiento no está definido.
Ejemplo Práctico:
#include <iostream>
#include <cctype>
int main() {
char c = 'A';
if (isalpha(c)) {
std::cout << c << " es una letra." << std::endl;
if (islower(c))
std::cout << c << " es minúscula." << std::endl;
else if (isupper(c))
std::cout << c << " es mayúscula." << std::endl;
} else if (isdigit(c)) {
std::cout << c << " es un dígito." << std::endl;
} else if (isspace(c)) {
std::cout << c << " es un espacio en blanco." << std::endl;
} else {
std::cout << c << " es un carácter especial." << std::endl;
}
// Conversión de mayúscula a minúscula
char lower = tolower(c);
std::cout << "Minúscula de " << c << ": " << lower << std::endl;
return 0;
}
Salida:
A es una letra.
A es mayúscula.
Minúscula de A: a
Casos Prácticos
Validar entradas de usuario: Asegúrate de que los caracteres ingresados sean válidos (alfabéticos,
numéricos, etc.).
Análisis de texto: Detecta letras, dígitos, espacios en blanco, etc.
Conversión de texto: Convierte caracteres a mayúsculas o minúsculas.
Convertir a mayúscula:
char letra = 'a';
letra = toupper(letra); // Convierte 'a' a 'A'
Convertir a minúscula:
Es letra:
Es dígito:
Es un espacio en blanco:
int main() {
cout << "Digite la barra espaciadora: ";
char espacio;
cin >> noskipws >> espacio; // Leer incluso espacios, si marcara error usar std::noskipws
return 0;
}
Uso de isspace:
En tu caso, quieres verificar exclusivamente si el carácter es la barra espaciadora (' '). Por
eso, usamos directamente la comparación espacio == ' '.
noskipws en cin:
El manipulador noskipws evita que cin salte caracteres en blanco (como el espacio).
Sin esto, el programa no reconocerá correctamente la barra espaciadora como entrada.
Salida:
No presionó la barra espaciadora…
Es un manipulador de entrada que evita que cin ignore caracteres de espacio en blanco (como
espacios, tabulaciones o saltos de línea).
Esto es útil cuando deseas leer y procesar directamente espacios u otros caracteres que, de otro
modo, serían saltados por cin.
isspace:
Es una función que verifica si un carácter es un "carácter de espacio en blanco" (esto incluye
espacio, tabulación, nueva línea, etc.).
No es necesario usarla para verificar exclusivamente si un carácter es un espacio normal (' ');
en ese caso, simplemente comparas con ' '.
Ejemplo de uso:
char c = ' ';
if (isspace(c)) {
cout << "Es un carácter de espacio en blanco." << endl;
}
Ejemplo combinado:
Si quieres un programa donde captures un carácter y verifiques si es un espacio específico o
cualquier espacio en blanco, lo harías así:
#include <iostream>
#include <cctype> // Para isspace
int main() {
cout << "Digite un carácter (incluidos espacios): ";
char c;
cin >> noskipws >> c; // Leer espacios también
if (c == ' ') {
cout << "Específicamente presionó la barra espaciadora." << endl;
} else if (isspace(c)) {
cout << "Es un carácter de espacio en blanco (tabulación, nueva línea, etc.)." << endl;
} else {
cout << "No es un carácter de espacio." << endl;
}
return 0;
}
Salida esperada:
Si el usuario presiona la barra espaciadora:
En resumen:
0 si son iguales,
valor negativo si la primera es menor,
valor positivo si la primera es mayor.
if (strcmp(cadena1, cadena2) == 0) {
std::cout << "Las cadenas son iguales.\n";
} else {
std::cout << "Las cadenas son diferentes.\n";
}
f. Concatenar cadenas:
Usa strcat para concatenar dos cadenas.
if (pos != nullptr) {
std::cout << "Carácter encontrado en la posición: " << (pos - cadena) << "\n";
} else {
std::cout << "Carácter no encontrado.\n";
}
3. Ejemplo completo:
Aquí tienes un ejemplo que utiliza varias de estas funciones:
#include <iostream>
#include <cstring>
#include <cctype>
int main() {
char cadena1[] = "Hola";
char cadena2[20];
// Copiar cadena
strcpy(cadena2, cadena1);
std::cout << "Cadena copiada: " << cadena2 << "\n";
// Convertir a mayúsculas
for (int i = 0; cadena2[i] != '\0'; i++) {
cadena2[i] = toupper(cadena2[i]);
}
std::cout << "Cadena en mayúsculas: " << cadena2 << "\n";
// Comparar cadenas
if (strcmp(cadena1, cadena2) == 0) {
std::cout << "Las cadenas son iguales.\n";
} else {
std::cout << "Las cadenas son diferentes.\n";
}
// Longitud de cadena
std::cout << "Longitud de la cadena1: " << strlen(cadena1) << "\n";
return 0;
}
Resumen:
Librerías:
<iostream>: Entrada/salida estándar.
<cstring>: Manipulación de cadenas estilo C (funciones como strcpy, strlen, etc.).
<cctype>: Manipulación de caracteres (toupper, tolower, isalpha, etc.).
static_cast<>
El operador static_cast<> en C++ es una herramienta utilizada para realizar conversiones de tipos
de datos de manera explícita y controlada. Es parte del conjunto de operadores de conversión
proporcionados por el lenguaje y es preferido sobre las conversiones de tipo estilo C ((type))
debido a su claridad y seguridad.
¿Qué es static_cast<>?
Definición: Es un operador de conversión que realiza conversiones entre tipos compatibles en
tiempo de compilación.
Propósito: Facilitar conversiones seguras y específicas, verificadas por el compilador.
Uso principal: Conversiones entre tipos de datos primitivos, punteros, referencias y clases
relacionadas por herencia.
¿Cómo se usa?
La sintaxis básica de static_cast<> es:
static_cast<tipo_destino>(expresión)
tipo_destino: El tipo al que se desea convertir.
expresión: La expresión que se va a convertir.
Ejemplo básico: Conversión de datos primitivos
#include <iostream>
int main() {
double valor = 9.7;
int entero = static_cast<int>(valor); // Conversión explícita de double a int
std::cout << "Valor original: " << valor << "\n";
std::cout << "Valor convertido: " << entero << "\n";
return 0;
}
¿Dónde se usa?
static_cast<> es útil en una variedad de situaciones. Aquí están las más comunes:
float x = 3.14;
int y = static_cast<int>(x); // Redondea hacia abajo.
2. Conversión de punteros
Permite convertir punteros hacia arriba (upcasting) o hacia abajo (downcasting) en una jerarquía
de herencia, aunque no garantiza que sea seguro.
Limitaciones de static_cast<>
No es seguro en tiempo de ejecución: Para conversiones hacia abajo (downcasting) en jerarquías de
herencia, no realiza comprobaciones en tiempo de ejecución. Si la conversión es inválida, el
comportamiento es indefinido.
No se utiliza para conversiones de tipos no relacionados: Para conversiones seguras en jerarquías
de herencia, se debe usar dynamic_cast<>.
int main() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> distribucion(48, 122); // Números, letras mayúsculas y
minúsculas.
return 0;
}
Este ejemplo utiliza static_cast<> para convertir números enteros generados aleatoriamente en
caracteres ASCII.
Conclusión
static_cast<> es una herramienta fundamental para realizar conversiones explícitas en C++. Al
dominarlo, puedes escribir código más seguro, legible y compatible con las normas modernas de C+
+.
¿Qué es dynamic_cast<>?
Definición: Es un operador de conversión que convierte punteros o referencias de un tipo
base a un tipo derivado (o viceversa) dentro de una jerarquía de herencia.
Propósito: Realizar conversiones seguras entre tipos relacionados, verificando en tiempo
de ejecución si la conversión es válida.
Uso principal: Se utiliza comúnmente en herencia polimórfica (es decir, cuando las clases
tienen al menos una función virtual).
¿Cómo se usa?
La sintaxis básica de dynamic_cast<> es:
dynamic_cast<tipo_destino>(expresión)
class Base {
public:
virtual ~Base() {} // Necesario para el uso de `dynamic_cast`
};
int main() {
Base* basePtr = new Derivada; // Puntero base apuntando a una clase derivada
if (derivadaPtr) {
derivadaPtr->mostrar(); // Éxito en la conversión
} else {
std::cout << "Conversión fallida\n";
}
delete basePtr;
return 0;
}
¿Dónde se usa?
dynamic_cast<> se utiliza principalmente en las siguientes situaciones:
1. Herencia polimórfica
Cuando trabajas con clases que tienen al menos una función virtual, puedes convertir
punteros o referencias de un tipo base a un tipo derivado.
class Animal {
public:
virtual void sonido() = 0; // Clase abstracta
};
if (perro) {
perro->sonido(); // "Guau"
}
Características de dynamic_cast<>
Para punteros: Si la conversión no es válida, devuelve nullptr.
Para referencias: Si la conversión no es válida, lanza una excepción de tipo
std::bad_cast.
Requiere herencia polimórfica: Las clases deben tener al menos una función virtual para
usar dynamic_cast<>.
Ejemplo con referencias
#include <iostream>
#include <typeinfo>
class Base {
public:
virtual ~Base() {} // Necesario para `dynamic_cast`
};
int main() {
Base baseObj;
try {
Derivada& ref = dynamic_cast<Derivada&>(baseObj); // Lanza std::bad_cast
} catch (const std::bad_cast& e) {
std::cout << "Conversión fallida: " << e.what() << "\n";
}
return 0;
}
Ventajas de dynamic_cast<>
Limitaciones de dynamic_cast<>
Requiere funciones virtuales: No puede usarse en clases sin funciones virtuales.
Costo en rendimiento: Más lento que static_cast<> debido a la verificación en tiempo de
ejecución.
Solo para jerarquías de herencia: No puede usarse para conversiones fuera de este
contexto.
Ejemplo práctico completo
Supongamos que tienes una lista de animales y necesitas verificar su tipo en tiempo de
ejecución para realizar acciones específicas:
#include <iostream>
#include <vector>
#include <memory>
class Animal {
public:
virtual ~Animal() {}
virtual void sonido() = 0;
};
int main() {
std::vector<std::unique_ptr<Animal>> animales;
animales.emplace_back(std::make_unique<Perro>());
animales.emplace_back(std::make_unique<Gato>());
return 0;
}
Conclusión
dynamic_cast<> es una herramienta poderosa para trabajar con jerarquías polimórficas en
C++. Proporciona seguridad y flexibilidad al realizar conversiones entre tipos,
verificando que estas sean válidas en tiempo de ejecución. Sin embargo, su uso debe ser
justificado debido a su impacto en el rendimiento.
Conversión:
En C++, puedes trabajar con el tipo de dato char para manejar caracteres y utilizar su valor ASCII
fácilmente. Cada carácter tiene un valor numérico asociado en el estándar ASCII, y puedes
mostrarlo simplemente convirtiendo el char a un entero (int). A continuación, te muestro cómo
hacerlo con un ejemplo práctico:
#include <iostream>
int main() {
char letra; // Variable para almacenar el carácter
return 0;
}
Usamos char letra; para definir una variable que almacena un único carácter.
Entrada del usuario (cin):
cin >> letra; permite que el usuario ingrese un carácter. Solo se capturará el primer carácter
introducido.
Conversión a entero:
Código:
#include <iostream>
#include <string>
int main() {
string palabra;
return 0;
}
#include <iostream>
int main() {
char texto[100]; // Array para almacenar el texto
return 0;
}
Explicación:
std::cin.getline(texto, tamaño) permite leer una línea completa hasta el primer salto de línea (\
n) o hasta que se alcance el tamaño especificado.
#include <iostream>
#include <string>
int main() {
std::string texto;
return 0;
}
Explicación:
std::getline(std::cin, texto) lee todo el texto introducido hasta que se detecta un salto de
línea (\n).
#include <iostream>
#include <string>
int main() {
std::string texto;
int numero;
return 0;
}
1. ¿Qué es std::string?
std::string es una clase que representa una cadena de caracteres.
Proporciona una interfaz rica para manejar texto, como concatenación, comparación, extracción de
sub-cadenas, búsqueda, entre otras operaciones.
Internamente, administra dinámicamente su memoria, lo que lo hace más flexible y fácil de usar en
comparación con arreglos estáticos de caracteres (char[]).
Para usar string, debes incluir el encabezado:
#include <string>
int main() {
string saludo = "Hola Mundo"; // Inicialización directa
string nombre("Juan"); // Constructor
string mensaje; // Declaración sin inicializar
return 0;
}
Salida:
Hola Mundo
Hola, Juan
Bienvenido a C++
3. Operaciones comunes con std::string
a) Concatenación
Puedes combinar cadenas con el operador + o +=.
#include <iostream>
#include <string>
int main() {
string nombre = "Juan";
string saludo = "Hola, " + nombre; // Concatenación con +
saludo += "! Bienvenido."; // Concatenación con +=
return 0;
}
Salida:
b) Acceso a caracteres
Puedes acceder a un carácter específico usando índices (como en un arreglo).
#include <iostream>
#include <string>
int main() {
string texto = "Hola";
// Cambiando un carácter
texto[1] = 'e'; // Cambia 'o' por 'e'
cout << "Texto modificado: " << texto << endl;
return 0;
}
Salida:
Primer carácter: H
Texto modificado: Hela
c) Longitud de la cadena
Usa el método .length() o .size().
#include <iostream>
#include <string>
int main() {
string palabra = "Programación";
cout << "La longitud de la palabra es: " << palabra.length() << endl;
return 0;
}
Salida:
d) Subcadenas
Usa el método .substr() para extraer partes de la cadena.
#include <iostream>
#include <string>
return 0;
}
Salida:
Subcadena: Mundo
e) Búsqueda
Puedes buscar una subcadena o carácter con .find().
#include <iostream>
#include <string>
int main() {
string texto = "Bienvenido a C++";
if (posicion != string::npos) {
cout << "La palabra 'C++' se encuentra en la posición: " << posicion << endl;
} else {
cout << "No se encontró 'C++' en el texto." << endl;
}
return 0;
}
Salida:
f) Comparación
Puedes comparar cadenas con los operadores habituales (==, !=, <, >).
#include <iostream>
#include <string>
int main() {
string cadena1 = "Hola";
string cadena2 = "Mundo";
if (cadena1 == "Hola") {
cout << "Las cadenas son iguales" << endl;
}
return 0;
}
Salida:
g) Inserción y eliminación
Usa métodos como .insert(), .erase() y .replace().
#include <iostream>
#include <string>
int main() {
string texto = "Hola C++";
texto.insert(5, "Mundo "); // Inserta "Mundo " en la posición 5
texto.erase(9, 3); // Elimina 3 caracteres desde la posición 9
texto.replace(0, 4, "Adiós"); // Reemplaza los primeros 4 caracteres con "Adiós"
return 0;
}
Salida:
Adiós Mundo
std::string ajusta automáticamente su tamaño según el contenido. Con char[], debes definir
manualmente el tamaño.
• Interfaz rica:
std::string proporciona métodos listos para usar, como concatenación, búsqueda, extracción de
subcadenas, etc.
• Seguridad:
Evita errores comunes como desbordamientos de búfer, que ocurren con char[].
int main() {
string texto = "Hola Mundo";
// Reversión de la cadena
reverse(texto.begin(), texto.end());
return 0;
}
Salida:
odnuM aloH
#include <iostream>
#include <string>
using namespace std;
int main() {
string nombre;
cout << "¡Hola, " << nombre << "! Bienvenido." << endl;
return 0;
}
En este ejemplo:
1. Incluimos la biblioteca <string> para usar la clase std::string.
2. Declaramos una variable nombre de tipo std::string.
3. Usamos getline(cin, nombre) para leer el nombre del usuario. La función getline permite
leer una línea completa de entrada, lo cual es útil para capturar nombres completos que
pueden incluir espacios.
4. Finalmente, mostramos un mensaje de bienvenida utilizando el nombre ingresado.
Esto te permitirá solicitar el nombre de una persona y almacenarlo correctamente en una variable
de tipo std::string.
Ejemplo anterior donde solicitamos varios nombres y los guardamos dentro de un arreglo de tipo
std::string:
#include <iostream>
#include <string>
using namespace std;
int main() {
const int numNombres = 5; // Número de nombres a ingresar
string nombres[numNombres]; // Arreglo de strings
return 0;
}
En este ejemplo:
1. Definimos una constante numNombres para especificar cuántos nombres se van a ingresar.
3. Utilizamos un ciclo for para solicitar al usuario que ingrese los nombres y los almacenamos
en el arreglo utilizando getline(cin, nombres[i]).
Está diseñado para manejar correctamente los tamaños máximos de memoria en la arquitectura del
sistema, asegurando que los programas sean portables.
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
for (size_t i = 0; i < vec.size(); ++i) {
std::cout << "Elemento " << i << ": " << vec[i] << std::endl;
}
return 0;
}
#include <iostream>
int main() {
int arr[10];
std::cout << "Tamaño del array en bytes: " << sizeof(arr) << std::endl;
return 0;
}
Funciones de las bibliotecas estándar: Muchas funciones de la STL, como las que devuelven tamaños
(std::string::length(), std::vector::size()), tienen valores de tipo size_t.
int a = -1;
size_t b = 10;
¿Cómo se define?
npos está definido como un miembro estático constante dentro de las clases relacionadas con
cadenas:
-1: Como size_t es sin signo, el valor de -1 se convierte en el máximo valor posible de size_t.
Usos de npos
Indicar que no se encontró algo:
Cuando buscas un substring o carácter en una cadena, las funciones como find, rfind,
find_first_of, etc., devuelven npos si no encuentran el elemento buscado.
Ejemplo:
#include <iostream>
#include <string>
int main() {
std::string text = "Hola, mundo";
return 0;
}
Salida:
#include <iostream>
#include <string>
int main() {
std::string text = "Hola, mundo";
size_t pos = text.find("mundo");
if (pos != std::string::npos) {
std::string sub = text.substr(pos); // Obtener el substring desde 'mundo'
std::cout << "Substring: " << sub << std::endl;
}
return 0;
}
Salida:
Substring: mundo
Ventajas de usar npos
1. Legibilidad: Indica claramente que algo no fue encontrado.
2. Portabilidad: npos siempre tiene el valor correcto, incluso si el tamaño de size_t varía
entre arquitecturas.
3. Evita errores de rango: Sirve como una forma estándar de manejar búsquedas fallidas.
npos solo es válido en el contexto de clases relacionadas con cadenas o contenedores que lo
definan (como std::string, std::string_view).
La biblioteca de funciones
string.h en C
Es una colección de funciones para manejar cadenas de caracteres. Estas funciones trabajan con
cadenas que son arreglos de caracteres terminados en un carácter nulo (\0). Aunque en C++
generalmente usamos la clase std::string, las funciones de string.h son útiles en ciertos casos,
especialmente en programación de bajo nivel o sistemas embebidos.
Voy a explicarte las funciones más importantes de string.h, incluyendo las que mencionaste.
1. Incluir la biblioteca
Para usar estas funciones, debes incluir el encabezado <cstring> en C++, que es equivalente a
string.h en C.
#include <cstring>
#include <iostream> // Solo necesario si usas cout/cin en C++
2. Funciones principales
a) strlen: Longitud de una cadena
Esta función calcula la longitud de una cadena (sin contar el carácter nulo \0).
Prototipo:
#include <cstring>
#include <iostream>
int main() {
char texto[] = "Hola Mundo";
size_t longitud = strlen(texto);
cout << "La longitud de \"" << texto << "\" es: " << longitud << endl;
return 0;
}
Salida:
Prototipo:
Ejemplo:
#include <cstring>
#include <iostream>
int main() {
char origen[] = "Hola";
char destino[10];
return 0;
}
Salida:
Cadena destino: Hola
Prototipo:
Ejemplo:
#include <cstring>
#include <iostream>
int main() {
char str1[] = "Hola";
char str2[] = "Mundo";
if (resultado == 0) {
cout << "Las cadenas son iguales." << endl;
} else if (resultado < 0) {
cout << "\"" << str1 << "\" es menor que \"" << str2 << "\"" << endl;
} else {
cout << "\"" << str1 << "\" es mayor que \"" << str2 << "\"" << endl;
}
return 0;
}
Salida:
Prototipo:
Ejemplo:
#include <cstring>
#include <iostream>
int main() {
char cadena1[20] = "Hola";
char cadena2[] = " Mundo";
return 0;
}
Salida:
Prototipo:
#include <cstring>
#include <iostream>
int main() {
char texto[] = "Hola Mundo";
char subcadena[] = "Mundo";
if (resultado) {
cout << "Subcadena encontrada: " << resultado << endl;
} else {
cout << "Subcadena no encontrada." << endl;
}
return 0;
}
Salida:
Prototipo:
Ejemplo:
#include <cstring>
#include <iostream>
int main() {
char texto[] = "Hola Mundo";
if (resultado) {
cout << "Carácter encontrado en: " << resultado << endl;
} else {
cout << "Carácter no encontrado." << endl;
}
return 0;
}
Salida:
Prototipo:
Ejemplo:
#include <cstring>
#include <iostream>
int main() {
char origen[] = "Hola Mundo";
char destino[20];
return 0;
}
Salida:
3. Consideraciones importantes
Espacio en memoria: Asegúrate de que la cadena destino tenga suficiente espacio para evitar
desbordamientos.
Carácter nulo: Muchas funciones asumen que las cadenas terminan con \0. Si no lo tienen, pueden
ocurrir errores.
Alternativas modernas: En C++, se recomienda usar std::string en lugar de char[] por seguridad y
facilidad de manejo.
c. Operadores
Operadores Aritméticos:
+: Suma
-: Resta
*: Multiplicación
/: División
%: Módulo (resto de una división entre enteros)
Operadores de Asignación:
=: Asignación básica.
+=, -=, *=, /=, %=: Operadores de asignación compuesta (Ej. x += 1 es lo mismo que x = x + 1).
Operadores Relacionales:
== Igual a 2==2
!= No igual a 3!=9
> Mayor que 6 > 2
< Menor que 4 < 100
>= Mayor o igual que
<= Menor o igual que
Operadores Lógicos:
2. Estructuras de Control
En C++, las estructuras de control son fundamentales para dirigir el flujo de ejecución de un
programa. Estas incluyen estructuras condicionales, de bucle y de control de salto. A continuación
te explico cada una con ejemplos prácticos:
1. Estructuras Condicionales
a) if-else
La estructura if evalúa una condición; si es verdadera, ejecuta el bloque de código asociado. Si
es falsa, puede haber un bloque else que se ejecuta.
Ejemplo:
#include <iostream>
using namespace std;
int main() {
int num;
cout << "Ingresa un número: ";
cin >> num;
if (num > 0) {
cout << "El número es positivo." << endl;
} else if (num == 0) {
cout << "El número es cero." << endl;
} else {
cout << "El número es negativo." << endl;
}
return 0;
}
Explicación:
Este código evalúa si el número ingresado es positivo, negativo o cero, utilizando varias
condiciones if-else.
b) switch
El switch evalúa el valor de una variable y ejecuta el código dentro del caso que coincida con el
valor.
Ejemplo:
#include <iostream>
using namespace std;
int main() {
int opcion;
cout << "Selecciona una opción (1-3): ";
cin >> opcion;
switch (opcion) {
case 1:
cout << "Opción 1 seleccionada." << endl;
break;
case 2:
cout << "Opción 2 seleccionada." << endl;
break;
case 3:
cout << "Opción 3 seleccionada." << endl;
break;
default:
cout << "Opción no válida." << endl;
}
return 0;
}
Explicación:
Aquí, dependiendo del valor de opcion, se ejecuta un caso específico. Si el valor no coincide con
ningún caso, se ejecuta el bloque default.
El switch es una estructura de control que permite ejecutar diferentes bloques de código basados
en el valor de una expresión. Es particularmente útil cuando se tiene una única variable que puede
tomar varios valores discretos y se desea ejecutar un bloque de código diferente para cada uno de
esos valores.
switch (expresión) {
case valor1:
// Bloque de código si expresión == valor1
break;
case valor2:
// Bloque de código si expresión == valor2
break;
// Puedes añadir tantos case como necesites
default:
// Bloque de código si la expresión no coincide con ningún case
}
case valor::
La palabra clave case se utiliza para definir un valor con el que se comparará la expresión.
Si la expresión coincide con valor, el bloque de código correspondiente será ejecutado.
Los valores deben ser constantes, literales o constantes definidas con #define o const.
Los valores de los case deben ser únicos; no puede haber duplicados.
break:
#include <iostream>
using namespace std;
int main() {
int opcion = 2;
switch (opcion) {
case 1:
cout << "Elegiste la opción 1." << endl;
break;
case 2:
cout << "Elegiste la opción 2." << endl;
break;
case 3:
cout << "Elegiste la opción 3." << endl;
break;
default:
cout << "Opción no válida." << endl;
}
return 0;
}
Explicación:
Si opción es igual a 2, el switch evalúa cada case hasta encontrar una coincidencia.
En este caso, coincide con case 2:, por lo que se ejecuta cout << "Elegiste la opción 2." <<
endl;.
Después de ejecutar este bloque, el break detiene el switch, evitando que el código de los demás
case se ejecute.
Si opcion fuera un valor distinto de 1, 2 o 3, se ejecutaría el bloque bajo default.
Fall-Through
Si se omite el break, el control pasa al siguiente case, incluso si no coincide con la expresión.
Esto es conocido como fall-through.
int dia = 2;
switch (dia) {
case 1:
cout << "Lunes" << endl;
case 2:
cout << "Martes" << endl;
case 3:
cout << "Miércoles" << endl;
break;
default:
cout << "Día no válido" << endl;
}
En este caso, si día es igual a 2, se ejecutarán las instrucciones de case 2 y case 3 porque no
hay break en case 2. Esto puede ser útil en algunos escenarios, pero a menudo lleva a errores si
no se maneja cuidadosamente.
El switch también es muy útil en combinación con enum, lo que mejora la legibilidad del código.
switch (hoy) {
case Lunes:
cout << "Hoy es lunes." << endl;
break;
case Martes:
cout << "Hoy es martes." << endl;
break;
case Miercoles:
cout << "Hoy es miércoles." << endl;
break;
default:
cout << "Es otro día de la semana." << endl;
}
En este ejemplo, el uso de enum hace que el código sea más fácil de entender y mantener.
Consideraciones Adicionales
No hay Evaluación de Rangos: switch no permite evaluar rangos directamente (e.g., case x > 5:).
Para esto, deberías usar una estructura if-else.
switch con Expresiones de Carácter: También puedes usar switch con caracteres, dado que el tipo
char es tratado como un entero en C++.
Conclusión
El switch es una herramienta poderosa para manejar múltiples condiciones basadas en el valor de
una sola variable, ofreciendo una alternativa más clara y eficiente que múltiples if-else. Sin
embargo, es importante recordar que switch tiene sus limitaciones y no es adecuado para todas las
situaciones.
Evaluación de la Expresión:
El valor de la expresión evaluada se compara secuencialmente con cada uno de los valores
especificados en los case.
Cada case define un valor constante con el que se compara la expresión. Si se encuentra una
coincidencia, el flujo del programa entra en el bloque de código correspondiente a ese case.
Ejecución del Código:
Cuando se encuentra un case coincidente, se ejecuta el bloque de código asociado con ese case.
Sin break: Si no hay una instrucción break al final del bloque de código, el flujo continuará
ejecutando el siguiente case y el siguiente, independientemente de que coincidan o no (esto se
llama fall-through).
Con break: Si el bloque de código incluye una instrucción break, el flujo se detiene y el programa
sale del switch, continuando con la ejecución del código que sigue después del switch.
Si la expresión no coincide con ningún case, se ejecutará el bloque de código asociado al default,
si este existe.
El default es opcional, pero es útil para manejar cualquier caso que no haya sido específicamente
cubierto por los case.
Ejemplo para Demostrar el Comportamiento del switch
Consideremos un ejemplo para ilustrar el flujo de ejecución y cómo se comporta switch con y sin la
instrucción break.
#include <iostream>
using namespace std;
int main() {
int numero = 2;
switch (numero) {
case 1:
cout << "El número es 1" << endl;
break;
case 2:
cout << "El número es 2" << endl;
// Aquí no hay break
case 3:
cout << "El número es 3" << endl;
break;
case 4:
cout << "El número es 4" << endl;
break;
default:
cout << "Número no reconocido" << endl;
}
return 0;
}
El número es 2
El número es 3
Explicación:
Fall-Through:
Ejemplo Común
En algunos casos, el comportamiento de fall-through se usa intencionalmente. Por ejemplo, para
agrupar varios valores que ejecuten el mismo código:
#include <iostream>
using namespace std;
int main() {
char grado = 'B';
switch (grado) {
case 'A':
case 'B':
case 'C':
cout << "Pasaste con buena calificación." << endl;
break;
case 'D':
cout << "Pasaste con calificación baja." << endl;
break;
case 'F':
cout << "Reprobaste." << endl;
break;
default:
cout << "Grado no válido." << endl;
}
return 0;
}
Explicación:
En este ejemplo, los case 'A':, case 'B':, y case 'C': no tienen break entre ellos.
Si grado es 'A', 'B', o 'C', se ejecuta el mismo bloque de código que imprime "Pasaste con buena
calificación."
El break después de este bloque detiene el flujo antes de que se evalúe case 'D':.
Consideraciones Importantes
Evitar Fall-Through No Deseado: Si no necesitas un comportamiento de fall-through, siempre utiliza
break para evitar que el flujo continúe accidentalmente.
Tipo de Expresión: La expresión evaluada en el switch debe ser un tipo integral o enum. No se
pueden utilizar tipos de datos como float, double, o std::string directamente.
Valores de los case: Deben ser valores constantes y únicos. No pueden repetirse dentro del mismo
switch.
Conclusión
El switch es una herramienta eficiente para manejar múltiples condiciones basadas en una única
expresión. Su comportamiento está claramente definido por la presencia o ausencia de break, lo que
determina si el flujo continúa hacia el siguiente case o sale del switch. El uso correcto de
switch puede hacer tu código más legible y organizado cuando se enfrentan múltiples opciones
discretas.
2. Bucles
a) for
El bucle for se utiliza cuando conoces de antemano cuántas veces deseas repetir un bloque de
código.
Ejemplo:
#include <iostream>
using namespace std;
int main() {
for (int i = 1; i <= 5; i++) {
cout << "Iteración " << i << endl;
}
return 0;
}
Explicación:
Este bucle imprime las iteraciones desde 1 hasta 5. El bucle consta de una inicialización (int i =
1), una condición (i <= 5) y un incremento (i++).
Ejemplo:
#include <iostream>
using namespace std;
int main() {
int arr[] = {10, 20, 30, 40, 50};
int size = sizeof(arr) / sizeof(arr[0]); // Calcular el tamaño del arreglo
return 0;
}
Explicación:
#include <iostream>
using namespace std;
int main() {
for (int i = 0, j = 10; i < j; i++, j--) {
cout << "i: " << i << ", j: " << j << endl;
}
return 0;
}
Explicación:
Ejemplo:
#include <iostream>
using namespace std;
int main() {
for (int i = 1; esPar(i) == false; i = doble(i)) {
cout << "Valor de i: " << i << endl;
}
return 0;
}
Explicación:
La función doble() se usa en la parte de incremento para duplicar el valor de i en cada iteración.
La condición del for llama a la función esPar(), que verifica si i es par.
Ejemplo:
#include <iostream>
using namespace std;
int main() {
for (;;) {
cout << "Bucle infinito" << endl;
break; // Romper manualmente para evitar un bucle infinito real
}
return 0;
}
Explicación:
El bucle se ejecuta indefinidamente hasta que se encuentre con una instrucción break o similar.
Puedes utilizar for junto con punteros y sizeof para iterar sobre un arreglo de manera más
dinámica.
Ejemplo:
#include <iostream>
using namespace std;
int main() {
int arr[] = {1, 2, 3, 4, 5};
int *ptr = arr; // Apuntar al primer elemento del arreglo
return 0;
}
Explicación:
ptr apunta al inicio del arreglo, y se utiliza aritmética de punteros (*(ptr + i)) para acceder a
cada elemento del arreglo.
Ejemplo:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> numeros = {10, 20, 30, 40};
return 0;
}
Explicación:
auto deduce automáticamente el tipo de it, que es un iterador para el contenedor vector.
Se recorre el vector utilizando begin() y end().
Ejemplo:
#include <iostream>
using namespace std;
int main() {
int suma = 0;
for (int i = 0, j = 1; i < 10 && j < 100; i++, j += 10) {
suma += i + j;
cout << "i: " << i << ", j: " << j << ", suma: " << suma << endl;
}
return 0;
}
Explicación:
Ejemplo:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> numeros = {10, 20, 30, 40};
return 0;
}
Explicación:
Este bucle recorre automáticamente cada elemento en el vector numeros, y num representa el valor
de cada elemento.
Conclusión
El bucle for en C++ es extremadamente flexible y puede combinarse con diversas expresiones y
operadores como sizeof, funciones personalizadas, punteros, y más. Estas combinaciones permiten un
control más detallado sobre las iteraciones y el flujo del programa.
b) while
El bucle while repite un bloque de código mientras una condición sea verdadera.
Ejemplo:
#include <iostream>
using namespace std;
int main() {
int contador = 1;
return 0;
}
Explicación:
El bucle while sigue ejecutándose mientras la variable contador sea menor o igual a 5.
c) do-while
Este bucle es similar a while, pero garantiza que el código se ejecutará al menos una vez, ya que
la condición se evalúa después del primer ciclo.
Ejemplo:
#include <iostream>
using namespace std;
int main() {
int num = 0;
do {
cout << "Ingresa un número positivo (o negativo para salir): ";
cin >> num;
} while (num >= 0);
return 0;
}
Explicación:
El código solicita al usuario ingresar números positivos y se detiene cuando ingresa uno negativo.
La condición se evalúa al final, por lo que el código se ejecuta al menos una vez.
Ejemplo:
#include <iostream>
using namespace std;
int main() {
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break;
}
cout << "Número: " << i << endl;
}
return 0;
}
Explicación:
El bucle se detiene cuando el valor de i es 5 debido al break.
b) continue
El continue salta la iteración actual de un bucle y pasa a la siguiente.
Ejemplo:
#include <iostream>
using namespace std;
int main() {
for (int i = 1; i <= 5; i++) {
if (i == 3) {
continue;
}
cout << "Número: " << i << endl;
}
return 0;
}
Explicación:
Cuando i es 3, el continue omite esa iteración y no imprime el número 3.
c) return
El return se utiliza para salir de una función, devolviendo opcionalmente un valor.
Ejemplo:
#include <iostream>
using namespace std;
int main() {
int resultado = suma(5, 7);
cout << "Resultado: " << resultado << endl;
return 0;
}
Explicación:
La función suma devuelve la suma de dos números y el return en el main indica que la ejecución del
programa terminó correctamente.
Resumen
Condicionales: if, if-else, switch.
Bucles: for, while, do-while.
Control de salto: break, continue, return.
Tanto sizeof como length() se utilizan para obtener información relacionada con el tamaño de
estructuras o contenedores en C++, pero tienen diferencias importantes en cuanto a su uso y
propósito, especialmente cuando los aplicamos dentro de un bucle for. Veamos las diferencias entre
ellos:
1. sizeof
El operador sizeof se utiliza para obtener el tamaño (en bytes) de un tipo de dato o de un objeto
en memoria. Su uso más común es en arreglos o tipos de datos primitivos. Funciona en tiempo de
compilación, por lo que no depende del estado dinámico de los datos.
#include <iostream>
using namespace std;
int main() {
int arr[] = {10, 20, 30, 40, 50};
return 0;
}
Características de sizeof:
Tipo de dato primitivo: Se usa comúnmente para obtener el tamaño de un arreglo estático o una
variable en bytes.
Tiempo de compilación: Opera en tiempo de compilación, lo que significa que sizeof no puede
determinar el tamaño de estructuras dinámicas (por ejemplo, arreglos dinámicos).
Funciona solo con arreglos estáticos: No puedes usar sizeof para obtener el tamaño de arreglos
dinámicos (por ejemplo, punteros o std::vector).
Limitaciones:
2. length()
length() es una función miembro que se utiliza para obtener la longitud de ciertos contenedores,
como std::string, que devuelve el número de caracteres en la cadena. En std::vector, se usa una
función similar, size(), que devuelve el número de elementos en el vector.
Uso con std::string:
Ejemplo:
#include <iostream>
#include <string>
using namespace std;
int main() {
string texto = "Hola Mundo";
return 0;
}
Ejemplo:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> numeros = {1, 2, 3, 4, 5};
return 0;
}
Características de length()/size():
#include <iostream>
using namespace std;
int main() {
int arr[] = {10, 20, 30, 40, 50};
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> numeros = {10, 20, 30, 40, 50};
return 0;
}
Conclusión:
Usa sizeof cuando trabajes con arreglos estáticos y necesites calcular el número de elementos en
un arreglo en tiempo de compilación.
Usa length() (para cadenas) o size() (para contenedores de la STL) cuando trabajes con estructuras
dinámicas cuyo tamaño puede cambiar en tiempo de ejecución.
Biblioteca CMATH:
La biblioteca cmath en C++ es una de las más importantes para realizar operaciones
matemáticas avanzadas. Proporciona una amplia gama de funciones matemáticas que son
esenciales para cálculos científicos, análisis numérico, gráficos y mucho más.
1. Logaritmos
• log(x): Logaritmo natural (base e).
• log10(x): Logaritmo en base 10.
Ejemplo:
#include <iostream>
#include <cmath>
int main() {
double num = 100.0;
std::cout << "Logaritmo natural de " << num << " es: " << log(num) << std::endl;
std::cout << "Logaritmo base 10 de " << num << " es: " << log10(num) << std::endl;
return 0;
}
2. Operaciones trigonométricas
• sin(x), cos(x), tan(x): Seno, coseno y tangente (en radianes).
• asin(x), acos(x), atan(x): Arco seno, arco coseno y arco tangente.
Ejemplo:
#include <iostream>
#include <cmath>
int main() {
double angle = 45.0; // en grados
double radians = angle * M_PI / 180.0; // Convertir a radianes
return 0;
}
3. Raíces (como raíz cúbica)
• sqrt(x): Raíz cuadrada.
• cbrt(x): Raíz cúbica.
Ejemplo:
#include <iostream>
#include <cmath>
int main() {
double num = 27.0;
std::cout << "Raíz cuadrada de " << num << " es: " << sqrt(num) << std::endl;
std::cout << "Raíz cúbica de " << num << " es: " << cbrt(num) << std::endl;
return 0;
}
int main() {
double a = 10.5, b = 20.3;
std::cout << "Mayor entre " << a << " y " << b << " es: " << fmax(a, b) << std::endl;
std::cout << "Menor entre " << a << " y " << b << " es: " << fmin(a, b) << std::endl;
return 0;
}
5. Redondeo y truncamiento
• ceil(x): Redondea hacia arriba.
• floor(x): Redondea hacia abajo.
• round(x): Redondea al entero más cercano.
• trunc(x): Elimina la parte decimal.
#include <iostream>
#include <cmath>
int main() {
double num = 7.8;
std::cout << "Redondeo hacia arriba: " << ceil(num) << std::endl;
std::cout << "Redondeo hacia abajo: " << floor(num) << std::endl;
std::cout << "Redondeo al entero más cercano: " << round(num) << std::endl;
std::cout << "Elimina parte decimal: " << trunc(num) << std::endl;
return 0;
}
int main() {
double base = 2.0, exponente = 3.0;
int num = -5;
std::cout << base << " elevado a la " << exponente << " es: " << pow(base, exponente)
<< std::endl;
std::cout << "Valor absoluto de " << num << " es: " << abs(num) << std::endl;
return 0;
}
math:
• Es el encabezado de C heredado en C++ como math.h.
• Las funciones no están dentro del espacio de nombres std (funcionan como en C
puro).
• No tiene soporte para overloading, lo que significa que podría haber problemas con
tipos como float o long double si no se convierten explícitamente.
Ejemplo
#include <math.h>
printf("%f", sqrt(16.0)); // sqrt no está en std
Ejemplo Comparativo
Con cmath:
#include <iostream>
#include <cmath>
int main() {
std::cout << "Raíz cuadrada de 16: " << std::sqrt(16.0) << std::endl;
return 0;
}
Con math.h:
#include <stdio.h>
#include <math.h>
int main() {
printf("Raíz cuadrada de 16: %f\n", sqrt(16.0));
return 0;
}
Recomendación
• Usa cmath siempre que trabajes en C++ porque:
• Se integra con el paradigma orientado a objetos.
• Permite sobrecarga para trabajar con diferentes tipos numéricos.
• Está en el estándar de C++.
• Usa math.h solo si estás portando código de C o trabajando en un entorno puro de
C.