PUNTEROS
En esta sección se mostrarán los secretos de un concepto de programación muy importante: los
punteros (apuntadores). Para comprender adecuadamente este nuevo concepto.
Imagínese la memoria de la computadora como se muestra en la siguiente figura. Cada posición de
memoria puede almacenar un octeto de información y está identificada por un número
denominado dirección. Las direcciones de memoria se enumeran secuencialmente desde cero
hasta el tamaño de la memoria.
El siguiente programa ilustra varios aspectos del uso de la memoria y de los punteros.
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int valor; //Una posición de memoria para guardar un caracter
int *puntero; //Un puntero
valor = 97;
printf("%u => |%d| <= direccion y datos de valor. \n",&valor,valor);
puntero = &valor;
printf("%u => |%d| <= direccion y datos de puntero \n", &puntero, puntero);
printf("\n Valor almacenado en puntero = %d\n", puntero);
printf("Dirección de puntero : &puntero = %u\n",&puntero);
printf("Valor referenciado por puntero: *puntero = %d\n",*puntero);
system("PAUSE");
return EXIT_SUCCESS;
}
Programa en ejecución
Análisis del programa
Como podrás ver se declaran dos variables de tipo entero una que se llama valor y la otra
se llama puntero; fíjate que la variable puntero tiene un asterisco ( * ), esto quiere decir
que esta variable es de tipo puntero y que apuntará a la dirección de memoria de la
variable.
Si sigues la secuencia del programa ahora la variable valor se le asigna el dato 97.
Si analizas el lo que arroja el primer printf, verás la dirección de memoria asignado a la
variable valor (2293543) y podrás ver el dato almacenado en esa dirección de memoria
que es 97. ¿Cómo se imprime la dirección de memoria de la variable valor? La respuesta
es con: &valor, ¿Cómo se imprime el contenido de la variable? Únicamente mencionando
el nombre de la variable sin anteponer &.
La siguiente línea tiene una expresión de igualdad puntero=&valor; lo que realiza esta
línea es asignarle la dirección de memoria de la variable valor a la variable puntero. Esto es
posible porque recuerda que declaraste al identificador puntero como una variable de tipo
puntero anteponiendo el asterisco (*).
Siguiendo el flujo del programa en el siguiente printf muestra la siguiente salida 2293543 y
2293543. Analiza el por qué y coméntalo en clase.
La misma explicación tiene los siguientes dos printf.
En el último printf imprime en pantalla el dato 97, este dato es lo que tiene almacenado la
variable valor, ¿Cómo es posible esto? Pues porque estamos imprimiendo la variable
puntero pero observa que tiene un asterisco antes *puntero, por lo tanto, está
imprimiendo el valor de la variable que está en la dirección 2293543 de la memoria.
EL PASO DE VARIABLES CON PUNTEROS.
Se puede modificar el valor de una variable mediante el uso de punteros. Esto permite pasar más
de una valor desde una función hacia la función que la invocó.
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int *puntero; //Una puntero
int variable; //Una variable para guardar un valor
variable = 1;
puntero = &variable;
printf("Valor almacenado en variable = %d\n", variable);
printf("Valor almacenado en puntero = %d\n", puntero);
*puntero = 2;
printf("Numero valor almacenado en variable = %d\n", variable);
printf("Valor almacenado en puntero = %d\n", puntero);
system("PAUSE");
return EXIT_SUCCESS;
}
Análisis del programa:
Como notarás en el programa se declaran dos variables una de tipo int puntero *puntero y
otra int variable.
Siguiendo el flujo del programa al identificador variable se le asigna el dato 1.
En seguida a la variable puntero se le asigna la dirección de memoria de variable
(&variable).
En los siguientes dos printf se imprime el contenido de variable y la dirección de memoria
del identificador variable.
En seguida viene una expresión de asignación *puntero = 2; lo que pasa aquí es que se le
asigna el dato 2 en la dirección de memoria 2293539.
En los siguientes dos printf, podrás ver el valor de variable y la dirección de memoria del
identificador variable.
PASO DE VARIABLES.
Esta sección muestra otro método para pasar un valor desde la función llamada hacia la función
que la invoca: el uso de punteros.
Se trata de un mecanismo muy importante para el diseño de programas y, por lo tanto, es
conveniente prestar mucha atención a esta sección y estudiar detenidamente los programas que
se presentan en la misma.
Idea básica.
En el siguiente programa muestra un valor desde la función llamada a la función que realizó la
llamada. Obsérvese que cuando una función no tiene parámetros, esto se indica usando el tipo
void.
#include <cstdlib>
#include <iostream>
void llamame(int *p); //
using namespace std;
int main(int argc, char *argv[])
{
int x; //Variable que recibe lo devuelto por la función
x = 0;
printf("El valor de x es: %d\n",x);
llamame(&x);
printf("El nuevo valor de x es %d\n",x);
system ("PAUSE");
return 0;
}
void llamame(int *p)
{
*p = 5;
}
Análisis del programa:
Como podrás ver este programa es un ejemplo de cómo puedo alterar una variable local. Podrás
notar que la variable x es una variable local de la función main(), sin embargo a través del manejo
de un puntero puedo cambiar su valor desde otra función.
MANEJO DE PUNTEROS EN VECTORES.
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int vector[3];
int *ptr;
vector[0] = 10;
vector[1] = 20;
vector[2] = 30;
printf ("Moviendose por los Indices\n");
printf("Contenido de vector[0] => %d\n", vector[0]);
printf("Contenido de vector[1] => %d\n", vector[1]);
printf("Contenido de vector[2] => %d\n", vector[2]);
ptr = vector;
printf("\nMoviendose a traves de punteros\n");
printf("\nContenido del vector[0] => %d\n", *ptr);
printf("Contenido del vector[1] => %d\n", *(ptr+1));
printf("Contenido del vector[2] => %d\n", *(ptr+2));
system("PAUSE");
return EXIT_SUCCESS;
}
Análisis del programa:
Podrás notar que declararon dos variables, la primera es un vector para almacenar tres
datos de tipo entero y la segunda una variable de nombre ptr de tipo puntero; como ya lo
hemos visto para declarar esta variable de tipo puntero hay que definirla con el asterisco
(*).
En la segunda parte del programa se les asignan valores al vector.
Los siguientes printf imprimen el valor de cada posición del vector con ayuda de los
índices.
En la igualación ptr = vector existe una diferencia muy notable cuando pasa la dirección de
una variable que no es de tipo arreglo a una que si lo es. Notarás que para pasar la
dirección de memoria de una variable que no está definida como arreglo tienes que usar el
&; en las variables que son declaradas como arreglos no tienes que hacer esto,
únicamente haces la igualdad y automáticamente C pasa la dirección de memoria, ojo esto
solamente puede suceder con vectores.
Los siguientes impresiones de pantalla los datos contenidos en el vector son obtenidos a
través de la dirección de memoria.
ENVIANDO DATOS DE UNA VECTOR A UNA FUNCIÓN.
#include <cstdlib>
#include <iostream>
void funcion(int v[]);
using namespace std;
int main(int argc, char *argv[])
{
int vector[3];
vector[0] = 10;
vector[1] = 20;
vector[2] = 30;
funcion(vector);
system("PAUSE");
return EXIT_SUCCESS;
}
void funcion(int v[])
{
printf("Contenido de vector[0] => %d\n", v[0]);
printf("Contenido de vector[1] => %d\n", v[1]);
printf("Contenido de vector[2] => %d\n", v[2]);
}
Análisis del programa:
Observe que el vector se denomina v[ ]. El operador de dirección * no se ha utilizado
(aunque podría haberse utilizado) debido a que v[ ] es un puntero que apunta al primer
elemento del vector.
Nótese que el argumento real no utiliza el operador &. Podría haberse utilizado
&vector[0], sin embargo, vector es la dirección de comienzo del vector y esto es lo que se
pasa a la función.
A continuación, función( ), recibe el valor de la dirección del primer elemento del vector y
produce a imprimir los valores de sus tres primeros elementos.
Para entender mejor vea la siguiente figura.
#include <cstdlib>
#include <iostream>
void funcion(int *v);
using namespace std;
int main(int argc, char *argv[])
{
int vector[3];
vector[0] = 10;
vector[1] = 20;
vector[2] = 15;
funcion(&vector[0]);
system("PAUSE");
return EXIT_SUCCESS;
}
void funcion(int *v)
{
printf("Contenido de vector[0] => %d\n", v[0]);
printf("Contenido de vector[1] => %d\n", v[1]);
printf("Contenido de vector[2] => %d\n", v[2]);
}
DEVOLVER LOS VALORES DE UN VECTOR POR MEDIO DE UNA FUNCIÓN
#include <cstdlib>
#include <iostream>
void funcion(int v[]);
using namespace std;
int main(int argc, char *argv[])
{
int vector[3];
funcion(vector);
printf("Contenido de vector[0] => %d\n", vector[0]);
printf("Contenido de vector[1] => %d\n", vector[1]);
printf("Contenido de vector[2] => %d\n", vector[2]);
system("PAUSE");
return EXIT_SUCCESS;
}
void funcion(int v[])
{
v[0] = 10;
v[1] = 20;
v[2] = 30;
}
Análisis del programa:
El paso de un vector numérico de vuelta de una función implica que se pase el vector entero. Lo
que realmente ocurre, es que cuando se pasa un vector a una función, no se pasan los valores de
los elementos del vector, sino simplemente la dirección de comienzo del mismo. Por tanto, la
función llamada puede utilizar esta dirección para escribir nuevos valores en las posiciones de
memoria reservadas para el vector numérico. Por lo tanto no requiere un return ya que se está
trabajando con la dirección de memoria.
NOTA: Cuando se usa una matriz de más de una dimensión, se necesitan especificar en el
parámetro formal el límite del resto de las dimensiones de la matriz. Esta exigencia de C se debe a
la manera cómo se almacenan en memoria las matrices. En el caso de una matriz de dos
dimensiones, el compilador necesita saber cuántas columnas hay en cada fila para acceder
correctamente a la matriz.
Ejemplo: void (sumar_columnas(int matriz_ent[ ][3], int valor_columna[ ]);