Como se escribió al inicio de este apartado tenemos estructuras de datos dinámicas, las que se constituyen en la opción a utilizar en algunos lenguajes como C++, en el que los arreglos vectoriales y matriciales son estáticos limitando el uso variable de datos. Para ello contamos con los llamados punteros o apuntadores.
Llamados también punteros, los apuntadores son variables que contienen una dirección de memoria, y que corresponde a un dato o a una variable que contiene ese dato.
Operadores para trabajar con apuntadores
Existen dos operadores para poder trabajar con punteros, sin ellos es imposible utilizar este tipo de datos. Estos son el “&” llamado ampersand, y el “*” llamado asterisco. Estos operadores tienen asignadas funciones muy específicas para cada uno, en tal sentido se utilizan según se necesite. Si anteponemos al identificador de la variable un signo & estamos indicando que utilizamos la dirección de memoria de dicha variable, por ello se le suele llamara operador de dirección.
En el caso del operador “*”, este utiliza la dirección de una variable y retorna el valor almacenado en esa posición de memoria, por tal motivo se le acostumbra llamar operador de indirección.
La sintaxis para declarar en puntero es:
tipo *identificador
De esta forma se declara que la variable contiene una dirección de memoria, que puede ser referenciada, donde tipo puede ser cualquier tipo ya sea entero, real, carácter o cadena, por ejemplo, y éste define sí y sólo sí el tipo de variable al que va a apuntar el puntero.
El nombre de la variable va después del modificador u operador de indirección *, el que nos diría en un seudo lenguaje: “puntero hacia…”.
Ejemplo:
Entero *apuntador, j;
Esta sentencia declara que apuntador apunta a un valor u objeto de tipo entero. Al declarar una variable como puntero.
Los punteros se deben inicializar a 0, NULL o a una dirección, al declararlos o bien utilizando el operador de asignación.
Ejemplo:
entero *p, k;
p = &k;
Cualquier variable utilizada en programación de computadores tiene asociada una dirección de memoria, así por ejemplo, las siguientes líneas de pseudocódigo dan como salida la dirección de k.
int k
k = 50
Escriba(“La dirección de memoria es “, &k)
Fin
Veamos otro ejemplo codificado en C++
En el ejemplo anterior, se leen dos números enteros, se calcula su resto. Se muestran por pantalla los números leídos, el resto y la correspondiente posición de memoria para cada variable, A continuación, una captura de pantalla del código ejecutado.
Como puede observarse, declaramos tres variables llamadas num1, num2 y resto que contiene un valor leído o asignado, para mostrarlo en pantalla solo tenemos que hacer como lo hemos hecho desde siempre, imprimiendo la variable. Ahora, si al principio de la variable agregamos el operador de dirección, hará la acción de convertirse en punteros y por eso vemos que la ejecución del programa nos está mostrando en pantalla el valor de las variables con la correspondiente posición de memoria de cada uno por haber agregado el operador &.
Los apuntadores son usados principalmente para crear estructuras de datos, y el uso más común es para el ahorro de memoria gracias a que el tipo de memoria usada es dinámica. La memoria dinámica permite que se expanda la capacidad de datos o se eliminen y se usen los necesarios. Para esta función se utiliza los operadores new y delete.
New se encarga de reservar el número de bytes necesarios para poder declarar y delete se coloca al final del programa, es el que borra el bloque de bytes reservado al principio para así en conjunto con new utilizar sólo la cantidad de memoria necesaria. Veamos el siguiente ejemplo.
Ejemplo:
Se desea obtener el peso promedio de los estudiantes de una escuela, para ello se requiere almacenar en un vector peso los datos obtenidos. Se debe mostrar por pantalla los pesos almacenados y el peso promedio de toda la población estudiada.
Solución:
Algoritmo
Inicio
Int num=0, *peso=NULL, sumatoria=0, prom = 0
Escriba(“Teclee el número de estudiantes: “)
Lea(num)
Peso = new int[num]
Para(int i = 0; i < num; i++)
Escriba(Ingrese el peso: )
Leer(peso[i])
Sumatoria = sumatoria + peso[i]
Fin-para
prom = sumatoria / num
Escriba(Los pesos registrados son: )
Para(int i = 0; i < num; i++)
Escriba(peso[i]
Fin-para
Escriba(“El promedio es: “, prom)
Delete []peso
Fin
Código C++
Ejemplo:
A partir de una matriz m x n leída por teclado escribir la transpuesta n x m. Se deben leer m y n para generar un arreglo dinámico.
Algoritmo
Inicio
int m, n, **arreglo = NULL;
Escriba(“Teclee el número de filas y de columnas ")
Leer(m, n)
arreglo = new int* [m];
para(int i = 0; i < m; i++)
arreglo[i] = new int[n];
fin-para
Escriba("Digite " ,m * n, " enteros.\n")
para(int i = 0; i < m; i++)
para(int j = 0; j < n; j++)
Leer(arreglo[i][j])
fin-para
fin-para
Escriba("Matriz original")
para(int i = 0; i < m; i++)
para (int j = 0; j < n; j++)
Escriba(arreglo[i][j])
fin-para
fin-para
Escriba("Matriz transpuesta")
para(int i = 0; i < n; i++)
para(int j = 0; j < m; j++)
Escriba(arreglo[j][i])
fin-para
fin-para
delete[]arreglo
Fin
Código C++
Ejemplo:
Se pide escribir el pseudocódigo de un programa que calcule el producto de dos matrices Mat1 y Mat2 con asignación dinámica de memoria: Se debe pedir por teclado las dimensiones de la matriz Mat1 (filas y columnas) y las columnas de la matriz Mat2, ya que las filas tienen que ser igual a las columnas de Mat1 para poder ser multiplicadas.
La salida por consola debe mostrar las dimensiones de la matriz resultante y los datos de la matriz resultante.
Algoritmo
Inicio
int filas, cols1,cols2,
**Mat1 = NULL, **Mat2 = NULL, **MatP = NULL
Escriba(“Número de filas y columnas de la matriz 1: ")
Leer(filas, cols1)
Mat1 = new int* [filas], Mat2 = new int* [cols1],
MatP = new int* [filas]
para(int i = 0; i < filas; i++)
Mat1[i] = new int[cols1]
fin-para
Escriba(“El número de columnas de la matriz 2 “)
Leer(cols2)
para(int i = 0; i < cols1; i++)
Mat2[i] = new int[cols2]
fin-para
para(int i = 0; i < filas; i++)
MatP[i] = new int[cols2]
fin-para
Escriba("Digite " ,filas * cols1, " enteros para la matriz 1)
para(int i = 0; i < filas; i++)
para(int j = 0; j < cols1; j++)
Leer(Mat1[i][j])
fin-para
fin-para
Escriba("Digite " ,cols1 * cols2, " enteros para la matriz 2)
para(int i = 0; i < cols1; i++)
para(int j = 0; j < cols2; j++)
Leer(Mat2[i][j])
fin-para
fin-para
Escriba("Dimesiones de matriz producto: “, filas * cols2)
Escriba("Matriz resultante")
para(int i = 0; i < filas; i++)
para(int j = 0; j < cols2; j++)
Escriba(MatP[i][j]=Mat1[i][j]*Mat2[i][j]+
Mat1[i][j+1]* Mat2[i+1][j]+
Mat1[i][j+2]* Mat2[i+2][j])
fin-para
fin-para
delete[]Mat1
delete[]Mat2
delete[]MatP
Fin
Código C++