Pasar parámetros por punteros a funciones
Pasar direcciones a funciones: modificar valores y analizar el costo de indirección.
En C++, los parámetros de las funciones generalmente se pasan por valor (by value) o por referencia (by reference). Sin embargo, a veces una función necesita trabajar directamente con una dirección de memoria — en ese caso se utiliza el método de paso de parámetros por puntero. Este método permite modificar las variables directamente en la memoria sin copiarlas.
1. Diferencia entre paso por valor y paso por puntero
Cuando los parámetros se pasan por valor, se crea una copia de la variable original. Los cambios dentro de la función no afectan a la variable original. Cuando se pasan por puntero, la función accede directamente a la memoria original.
#include <iostream>
using namespace std;
void CambiarPorValor(int x) {
x = 20;
}
void CambiarPorPuntero(int *p) {
*p = 20;
}
int main() {
int numero = 10;
CambiarPorValor(numero);
cout << "Después de pasar por valor: " << numero << endl; // 10
CambiarPorPuntero(&numero);
cout << "Después de pasar por puntero: " << numero << endl; // 20
}
Conclusión: El paso de parámetros por puntero permite cambiar el valor de una variable directamente a través de su dirección de memoria.
2. Definición de parámetros de puntero
Cuando se declara una función con un parámetro de puntero, el tipo del parámetro se indica con *.
Al llamar a la función, la dirección de la variable se pasa con &.
void Modificar(int *ptr) {
*ptr = *ptr + 5;
}
Dentro de la función, la expresión *ptr cambia el valor real de la variable apuntada.
Este método ahorra memoria y mejora el rendimiento.
3. Múltiples parámetros de puntero
Es posible pasar varias direcciones de variables a una función al mismo tiempo. Este método es especialmente útil para operaciones aritméticas o para intercambiar valores.
#include <iostream>
using namespace std;
void Intercambiar(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 5, y = 10;
Intercambiar(&x, &y);
cout << "x: " << x << ", y: " << y << endl; // x:10, y:5
}
En este ejemplo, los parámetros de puntero permiten acceder directamente a las direcciones de memoria de las variables. Los valores fuera de la función se modifican correctamente.
4. Parámetros de puntero const
Si una función no debe modificar el valor recibido,
el parámetro de puntero puede declararse como const.
void Imprimir(const int *p) {
cout << "Valor: " << *p << endl;
}
int main() {
int numero = 42;
Imprimir(&numero);
}
En este caso, la función solo puede leer los datos, no modificarlos. Esto aumenta la seguridad del código y evita manipulaciones accidentales.
5. Punteros y arreglos (parámetros de arreglo)
En C++, los arreglos se comportan como punteros. Cuando se pasa un arreglo a una función, se pasa la dirección de su primer elemento.
void ImprimirArreglo(int *arr, int longitud) {
for (int i = 0; i < longitud; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
int main() {
int numeros[] = {10, 20, 30, 40, 50};
ImprimirArreglo(numeros, 5);
}
Dentro de la función, se puede acceder a los elementos con arr[i] o *(arr + i).
El nombre del arreglo representa la dirección de su primer elemento.
6. Parámetros de puntero y memoria dinámica
Los parámetros de puntero también pueden usarse con datos creados dinámicamente en el heap.
#include <iostream>
using namespace std;
void Rellenar(int *p, int longitud) {
for (int i = 0; i < longitud; i++)
p[i] = (i + 1) * 10;
}
int main() {
int *arreglo = new int[5]; // Arreglo dinámico en el heap
Rellenar(arreglo, 5);
for (int i = 0; i < 5; i++)
cout << arreglo[i] << " ";
delete[] arreglo; // Liberar memoria
}
En este ejemplo, el parámetro de puntero se utiliza para llenar los elementos de un arreglo asignado en el heap.
Después de la llamada a la función, la memoria debe liberarse con delete[].
7. Puntero a puntero (doble puntero)
También se puede almacenar la dirección de un puntero. En este caso, se utiliza un puntero a puntero. Esto es útil cuando una función necesita cambiar el propio puntero.
void CambiarPuntero(int **p) {
static int valor = 99;
*p = &valor; // cambia la dirección a la que apunta el puntero
}
int main() {
int x = 10;
int *ptr = &x;
CambiarPuntero(&ptr);
cout << "Nuevo valor: " << *ptr << endl; // 99
}
Este método permite que la función modifique no solo los datos, sino también el propio puntero. Se usa comúnmente en funciones que gestionan memoria dinámica.
8. Alternativas modernas en C++: Referencias y Smart Pointers
Con el C++ moderno (C++11 y posteriores), los parámetros de puntero clásicos a menudo se reemplazan por referencias o punteros inteligentes (smart pointers):
int&→ seguro, no puede ser nulo, no requiere gestión manual de memoria.std::unique_ptr→ mantiene propiedad exclusiva del objeto.std::shared_ptr→ permite compartir un objeto entre varios propietarios.
Sin embargo, en la programación de sistemas, sistemas embebidos o aplicaciones críticas de rendimiento, los parámetros de puntero clásicos siguen siendo ampliamente utilizados.
9. TL;DR
int *p→ define un parámetro de puntero; se llama con&var.- Los parámetros de puntero permiten acceder y modificar la memoria directamente.
const int *p→ solo lectura.- Los arreglos se comportan como punteros y se pasan como direcciones.
int **p→ puntero a puntero; la función puede cambiar el propio puntero.- En C++ moderno, las
referenciasy lossmart pointersson más seguros. - Todos los ejemplos pueden ejecutarse con Visual Studio 2022 o GCC 11+.