El Problema Real: Tienes una función que lee un sensor DHT11. Necesitas que esa función te devuelva DOS valores: Temperatura y Humedad. Pero en C++, un return solo puede devolver un único valor.
// ESTO NO FUNCIONA.
// Arduino hace una COPIA de temp y hum. Modifica la copia y la destruye al salir.
void leerSensorMal(float temp, float hum) {
temp = 25.5;
hum = 60.0;
}
void setup() {
Serial.begin(9600);
// 1. Las variables originales (Los cajones reales en la memoria)
float temperatura_real = 0.0;
float humedad_real = 0.0;
// 2. Usamos '&' para obtener la DIRECCIÓN de esos cajones
leerSensorPro(&temperatura_real, &humedad_real);
// 3. ¡Magia! Los valores cambiaron desde adentro de la función.
Serial.print("Temp: "); Serial.println(temperatura_real); // Imprime 25.5
Serial.print("Hum: "); Serial.println(humedad_real); // Imprime 60.0
}
// El '*' en los parámetros significa: "Voy a recibir una dirección de memoria"
void leerSensorPro(float* ptrTemp, float* ptrHum) {
// El '*' antes del nombre significa: "Desreferenciar" (Ve a esa dirección y mete este dato)
*ptrTemp = 25.5;
*ptrHum = 60.0;
}
void loop() {}
2) Estructura
El Problema Real: Estás programando un GPS. Necesitas registrar Latitud, Longitud, Altitud, Número de Satélites y Velocidad. Si creas 5 variables sueltas por cada GPS, tu código será ilegible y será fácil equivocarse al pasarlas a otras funciones.
// 1. Creamos el MOLDE (Esto no ocupa memoria todavía)
struct DatosGPS {
float latitud;
float longitud;
int altitud;
byte satelites;
};
void setup() {
Serial.begin(9600);
// 2. Fabricamos una caja real usando el molde (Ocupa 4+4+2+1 = 11 bytes)
DatosGPS miUbicacion;
// 3. Llenamos la caja usando el operador PUNTO (.)
miUbicacion.latitud = 40.4168;
miUbicacion.longitud = -3.7038;
miUbicacion.altitud = 650;
miUbicacion.satelites = 8;
Serial.print("Satelites conectados: ");
Serial.println(miUbicacion.satelites);
}
void loop() {}
3)
Categoría 3: El Colapso de la Memoria (Punteros a Structs)
El Problema Real: Tienes tu DatosGPS (11 bytes). Quieres pasarlo por 4 funciones: una para validarlo, otra para imprimirlo en un LCD, otra para guardarlo en SD y otra para enviarlo por WiFi. Si lo pasas «normalmente», Arduino copiará esos 11 bytes 4 veces (44 bytes desperdiciados). Si el struct fuera más grande, te quedas sin RAM al instante.
La Solución Profesional: Pasar el puntero (la dirección). Un puntero en Arduino siempre ocupa solo 2 bytes, sin importar lo gigante que sea el struct al que apunta.
struct DatosGPS {
float latitud;
float longitud;
int altitud;
};
void setup() {
Serial.begin(9600);
DatosGPS ubicacion = {40.41, -3.70, 650}; // Inicialización rápida
// Pasamos la DIRECCIÓN del struct (solo movemos 2 bytes de memoria)
imprimirEnPantalla(&ubicacion);
}
void loop() {}
// La función recibe un puntero al struct
void imprimirEnPantalla(DatosGPS* ptrDatos) {
// REGLA DE ORO: Si usas un puntero a un struct, NO usas el punto (.)
// Usas la FLECHA (->). Significa: "Ve a la dirección y lee este miembro"
Serial.print("Lat: ");
Serial.println(ptrDatos->latitud);
Serial.print("Lon: ");
Serial.println(ptrDatos->longitud);
}
Cuando tengo la caja física en mis manos, uso un PUNTO (caja.dato). Cuando tengo un mapa que me dice dónde está la caja, uso una FLECHA (mapa->dato)
4)
El Problema Real: Tienes una lista de 100 lecturas de un sensor. Necesitas pasar esa lista a una función para calcular el promedio. ¿Cómo pasas 100 elementos sin colapsar la memoria?
El Secreto de C++: El nombre de un Array es, en secreto, un puntero camuflado que apunta al primer elemento.
void calcularPromedio(int* lista, int cantidad) {
long suma = 0;
for(int i = 0; i < cantidad; i++) {
// Magia: Podemos usar corchetes [] con un puntero!
suma = suma + lista[i];
}
Serial.print("Promedio: ");
Serial.println(suma / cantidad);
}
void setup() {
Serial.begin(9600);
// Un array de 5 elementos
int misLecturas[5] = {10, 20, 30, 40, 50};
// Al pasar "misLecturas", en realidad estamos pasando un puntero
// a la dirección de memoria del número '10'.
calcularPromedio(misLecturas, 5);
}
void loop() {}
«Un array es como una fila de casas contiguas. El compilador no necesita saber dónde están todas las casas. Solo necesita la dirección de la PRIMERA casa. Si sabe que cada casa mide 2 metros, para encontrar la casa 3, solo suma 6 metros a la dirección inicial. Eso es lo que hace el corchete [i].»
5)
Categoría 5: El Menú Infinito (Punteros a Funciones)
El Problema Real: Estás haciendo un menú para una pantalla OLED con 4 botones. Tienes 20 pantallas diferentes. Tu código se convierte en un infierno de if / else o un switch de 500 líneas.
La Solución Profesional: Las funciones (el código) también están guardadas en la memoria. Por lo tanto, ¡tienen dirección! Puedes crear una variable que «apunte» a la función que debe ejecutarse en ese momento.
// Dos funciones que hacen cosas distintas
void pantallaPrincipal() {
Serial.println("--- MENU PRINCIPAL ---");
}
void pantallaAjustes() {
Serial.println("--- AJUSTES ---");
}
void setup() {
Serial.begin(9600);
// 1. Declaramos un puntero a función.
// (Léase: Un puntero llamado 'pantallaActual' que apunta a funciones vacías)
void (*pantallaActual)() = nullptr;
// 2. Apuntamos a la primera función
pantallaActual = pantallaPrincipal;
// 3. LA EJECUTAMOS
pantallaActual(); // Imprime: --- MENU PRINCIPAL ---
delay(2000);
Serial.println("Usuario presiona boton 'Ajustes'...");
// 4. Cambiamos hacia dónde apunta
pantallaActual = pantallaAjustes;
// 5. Ejecutamos exactamente la misma variable, pero hace otra cosa
pantallaActual(); // Imprime: --- AJUSTES ---
}
void loop() {}






