Sunteți pe pagina 1din 23

APUNTADORES INTRODUCCION

Objetivos

Adquirir destrezas sobre el uso de punteros tanto en C como en C++.


Comprender la relacin existente entre apuntadores y matrices.
Repasar los conceptos tericos vistos a lo largo de la materia

Indice

1. Qu son los apuntadores?


2. Referenciando apuntadores.
3. Deseferenciando un apuntador.
4. Usos de apuntadores.
4.1. Funciones y apuntadores.
4.2. Arreglos y apuntadores.
4.2.1. Aritmtica de punteros.
4.2.2. Apuntadores y arreglos multidimensionales.
4.2.3. Accediendo a los elementos de una matriz.
4.3. Apuntadores a apuntadores.

Contenido

1. Que son los apuntadores

Un apuntador es una variable que almacena una direccin de memoria. Lo primero que se debe
hacer al trabajar con apuntadores es declararlos, la forma como se declara un apuntador se
muestra a continuacin:

tipo *[modificadores_del_tipo] nombre [=valor inicial];

Donde1:
Tipo: Tipo de dato al cual se desea apuntar, puede ser un tipo de dato simple (char, int, etc) o
un tipo de dato complejo como una estructura o una clase.
Modificadores del tipo: Puede contener cualquier combinacin de los modificadores de tipo
const, volatile y restrict.
Nombre: Nombre del apuntador.
Valor inicial: Valor inicial del apuntador.

Por ejemplo, supngase que se declar un puntero a una variable la cual tiene el valor de 5 tal y
como se muestra a continuacin:

int theVariable = 5;
int *pPointer = &theVariable;

1
Las cosas que se encuentran entre corchetes son opcionales.
En la siguiente figura se muestra el efecto en memoria de la declaracin anterior:

Como se puede apreciar el valor almacenado en el apuntador es la direccin de memoria de la


variable a la cual est apuntando. Esto fue posible gracias al operador direccin (&). Con base en la
figura anterior se construy la siguiente tabla para clarificar su uso:

Significado Valor
theVariable Contenido de theVariable 5
&theVariable Direccion de theVariable 101
pPointer Contenido del apuntador pPointer 101
&pPointer Direccion del apuntador pPointer 106

Como se puede notar de la tabla anterior el valor obtenido con el operador & es la direccin en la
cual se encuentra la variable en cuestin. Como una variable puede ocupar ms de 1 byte, el valor
resultante es el byte asociado a la direccin base de la variable.

Ahora bien, con el apuntador es posible acceder a cualquier lugar de memoria y modificar su valor.
Para ello se tiene que referenciar y desreferenciar el apuntador. Esto se describe a continuacin:

2. Referenciando apuntadores

Consiste en asociar el apuntador a una direccin especfica, para esto se suele usar el operador &
para obtener la direccin de la variable en cuestin. A continuacin se muestra la forma como
normalmente se hace esto:

apuntador = &variable;

Tambin es posible referenciar un apuntador pasndole el valor que se tiene en otro apuntador.
Note que no se hizo uso del operador & en este caso:

apuntador1 = apuntador2;
Todo apuntador debe inicializarse antes de usarse. Si esto no se hace, cuando intente usarlo para
hacer alguna operacin en memoria el programa sacara un error. Un puntero que no ha sido
inicializado se conoce como Wild pointer.

En la siguiente figura se ilustra un poco mejor lo anterior:

int i,j;
int *p; //Apuntador a un entero

Hasta el momento solo se ha declarado el apuntador pero no se ha referenciado, en la siguiente


figura se muestra el efecto de referenciar el apuntador:

p = &i;

Es posible que varios punteros estn apuntando a un mismo lugar de memoria:

int i;
int *p,*q,*r;
p = &i;
q = &i;
r = p;
3. Deseferenciando un apuntador

Para poder acceder al lugar de memoria que est siendo apuntado por el puntero y realizar
operaciones de lectura y escritura sobre este el puntero se debe desreferenciar. Para ello se hace
uso del operador desreferencia (*).

El valor del lugar de memoria apuntado se obtiene de la siguiente manera:

variable = *apuntador;

Ahora si lo que se desea hacer es escribir en el lugar de memoria apuntado se hace lo siguiente:

*apuntador = valor;

La siguiente figura muestra el resultado de desreferenciar un apuntador:

*p = 5;

Como se puede notar de la figura anterior, es posible modificar el valor de i desde el apuntador.
Vale resaltar que todo apuntador antes de ser desreferenciado debi haber sido previamente
inicializado con una direccin valida.

4. Usos de los apuntadores

Los apuntadores se usan principalmente para 3 cosas:


Crear estructuras de datos dinmicas.
Manejar parmetros variables pasados a funciones.
Acceder de a los diferentes elementos de arreglos o estructuras.

A continuacin se trata con ms detalle cada una de estas aplicaciones.

4.1 Funciones y apuntadores

Existen dos maneras de hacer llamados a funciones, por referencia y por valor. Cuando se realiza
un llamado por valor; se trabaja sobre una copia de la variable pasada como argumento y por lo
tanto la variable original (la que se pas como argumento) no se modifica. Por otro lado, cuando
se realiza una llamada por referencia al estar accediendo al lugar de memoria en el que se
encuentra la variable pasada como argumento es posible modificar el valor original de la variable
pasada como argumento.
El paso de funciones por referencia es de extrema utilidad cuando los argumentos que se estn
pasando a la funcin son pesados ya que esto evita que se tengan que hacer copias de dichos
argumentos que en el peor de los casos pueden ocasionar que el programa colapse por llenar
stack. Tambin, mediante el uso de apuntadores, es posible superar la restriccin que se tiene en
la cual una funcin no puede retornar ms de un elemento; as, por medio de referencias es
posible retornar un array por ejemplo.

Para indicar que una funcin ser pasada por referencia, se emplean apuntadores en la cabecera
de la funcin, esto porque lo que se pasa como argumento es la direccin de memoria. Por
ejemplo:

tipo_retorno f(tipo_1 *pName_1,tipo_2 *pName_2,...,tipo_N *pName_N)

Para aterrizar un poco ms lo anterior, supongamos esta funcin:

void swap(int *px, int *py) {


int temp;
cout << "Swap. Before swap, *px: " << *px <<
" *py: " << *py << endl;
temp = *px;
*px = *py;
*py = temp;
cout << "Swap. After swap, *px: " << *px <<
" *py: " << *py << endl;

Como se pueden notar en la definicin de la funcin anterior, en este caso ambos argumentos son
pasados por referencia.

Ahora en lo que respecta a la invocacin si lo que se pasa es como parmetro es una variable
como tal se debe hacer uso del operador & para obtener la direccin de dicha variable y as
inicializar el apuntador que funciona como argumento. Por otro lado si lo que se est pasando es
un apuntador a una variable, no es necesario usar el operador & ya que el valor almacenado en
este ser una direccin de memoria. La siguiente tabla ilustra esto:

Caso Invocacion Observaciones


Se est pasando una int x = 5, y = 10; Es necesario usar el operador & para
variable a una funcin swap(&x,&y); obtener la direccin de memoria de las
que se llama por variables y as poder inicializar lo
referencia apuntadores que funcionan como
argumentos.
Se est pasando int x = 5, y = 10; Como lo que se pasan son apuntadores
apuntador a una int *px = &x, *py; previamente inicializados, estos ya tienen
py = &y;
funcin que se llama swap(px,py);
la direccin de memoria de la variable que
por referencia ser pasada como argumento de la
funcin, por lo tanto no es necesario usar
el operador &.
Qu sucede si lo que se pasa como argumento es lo resaltado?

int x = 5, y = 10;
int *px = &x, *py;
py = &y;
swap(&px,&py);

Codifique y compile el siguiente cdigo:

// Demuestra el uso de funciones por referencia


#include <sdtio.h>

void swap(int *x, int *y);


void swapv(int x, int y);

int main() {
int x = 5, y = 10;
printf("---------------------------------------------------\n");
printf("Llamada por valor \n");
printf("Main. Antes del swap; x: %d, y: %d \n");
swapv(x,y);
printf("Main. Despues del swap; x: %d, y: %d \n");
printf("---------------------------------------------------\n");
printf("Llamada por referencia \n");
printf("Main. Antes del swap; x: %d, y: %d \n");
swapr(&x,&y);
printf("Main. Despues del swap; x: %d, y: %d \n");
printf("---------------------------------------------------\n");
return 0;
}

void swapr(int *px, int *py) {


int temp;
printf("Swapr. Antes del swap; *px: %d, *py: %d\n",*px,*py);
temp = *px;
*px = *py;
*py = temp;
printf("Swapr. Despues del swap; *px: %d, *py: %d\n",*px,*py);
}

void swapv(int x, int y) {


int temp;
printf("Swapv. Antes del swap; x: %d, y: %d\n",x,y);
temp = x;
x = y;
y = temp;
printf("Swapv. Despues del swap; x: %d, y: %d\n",x,y);
}
Preguntas:
Cul es la salida del cdigo anteriormente mostrado y por qu?
El siguiente fragmento de cdigo corresponde a una funcion la cual permite calcular el
producto escalar de dos vectores del mismo tamao:

// This function calculates the scalar product of two arrays.


// Arguments: Two arrays of double, and their length.
// The two arrays need not be distinct.

double scalar_product( const double * restrict p1,


const double * restrict p2,
int n )
{
double result = 0.0;
for ( int i = 0; i < n; ++i )
result += p1[i] * p2[i];
return result;
}

Una funcin tambin puede retornar un apuntador cuando es invocada, para hacer esto, en la
definicin y declaracin de la funcin se debe indicar que la funcin retornara un apuntador lo
cual se hace precediendo el nombre de la funcin por un asterisco. A continuacin se muestra la
forma que debe llevar la funcin para este caso:

tipo_retorno *f(parametros...)

Observe el siguiente fragmento de cdigo, el cual consiste en la definicin de la funcin mayor:

int *mayor(int *a,int n) {


int i;
int *m = a;
a++;
for (i = 1; i < n; ++i )
if(*m < *a) {
m = a;
a++;
}
return m;
}

Note que lo realimente importante es que se declar un apuntador a un tipo de dato especfico, se
inicializo y luego se retorn este, en general en la definicin de la funcin se sigue la siguiente
plantilla:

tipo *funcion(tipo *arg1,...) {


tipo *ptr; // Declaracion del apuntador
ptr = &arg; // Inicializacion del apuntador

/** Operaciones **/


...
return ptr; // Retorno del apuntador
}
Preguntas:
Qu es lo que hace la funcin anteriormente definida?
El parmetro a es un vector, Cul es la otra forma alternativa de declarar la cabecera para la
funcin?
Qu es que se est haciendo en la primera lnea resaltada?, Con que otra instruccin puedo
hacer lo mismo?
Qu es lo que hace la segunda lnea resaltada?
Qu valor tendr m en la tercera lnea resaltada?

En lo que respecta a la declaracin de la funcin (prototipo de la funcion), esta puede ser hecha de
la siguiente forma:

int *mayor(int *a,int n);

O tambin puede ser de la siguiente forma, sin colocar los nombres de las variables que sirven
como argumentos:

int *mayor(int *,int);

Recuerde lo importante en la declaracin de la funcin es indicarle al compilador como van a


usarse los parmetros. Ahora lo que resta es probar la funcin, para ello esta debe ser invocada ya
sea dentro de la funcin main o dentro de otra funcin.

Evale la funcin anteriormente creada. Para ello, codifique el siguiente cdigo:

#include <stdio.h>

int *mayor(int *a,int n);

int main() {
int a[6] = {1,2,5,9,-1,3};
int *p;
p = mayor(a,5);
printf("El elemento mayor del vector es: %d\n",*p);
return 0;
}

int *mayor(int *a,int n) {


int i;
int *m = a;
a++;
for (i = 1; i < n; ++i )
if(*m < *a) {
m = a;
a++;
}
return m;
}
Note algo realmente importante, cuando se invoc la funcin se debi declarar previamente un
apuntador, el cual va a ser empleado para almacenar el valor retornado por la funcin.

4.2 Arreglos y apuntadores

4.2.1 Aritmtica de punteros

Como los apuntadores son variables es posible realizar operaciones matemticas sobre ellos, sin
embargo debido a que lo almacenado en estos son direcciones de memoria no todas las
operaciones convencionales que se podran hacer sobre una variable normal son posibles. Las
operaciones validas son:
Aadir o sustraer un entero de un apuntador. Esto hace que el puntero apunte a otro lugar de
memoria diferente al que inicialmente estaba apuntando esto debido a la modificacin de lo
que se encuentra almacenado en este.
Sustraer un apuntador de otro: Cuando se realiza esta operacin, los dos apuntadores deben
ser del mismo tipo.
Comparar dos apuntadores. La comparacin es comnmente empleada para comparar
cualquier puntero con el puntero a NULL usando los operadores de igualdad (== o !=).

Las tres operaciones anteriormente descritas son generalmente tiles para apuntadores que se
refieren a los elementos de un array. Recordemos que un array consiste de un conjunto de
variables del mismo tipo las cuales pueden ser accedidas bajo un mismo nombre. Cuando se
declara un array lo que sucede en memoria es que se reservan un conjunto de posiciones
contiguas en memoria tal y como se muestra en la siguiente figura:
Para ilustrar lo anterior suponga lo que tiene dos apuntadores, p1 y p2 los cuales estn apuntando
a los elementos de un array a:
Si p1 apunta al elemento i del array (a[i]), y n es un entero, entonces la expresin p2 = p1 + n
hace que p2 apunta al elemento a[i+n]. (Se asume que i+n est dentro del ndice del array).
La resta p2 p1 da el nmero de elementos del array entre los dos apuntadores.
La comparacin p1 < p2 es cierta si el elemento referenciado por p2 tiene un ndice ms
grande que el referenciado por p1, de otro lado la comparacin es falsa.

Lo anterior muestra que existe una relacin entre la forma de escribir un array con subndices y
escribirlo con apuntadores aritmtica de apuntadores, esto implica que:
El nombre de un arreglo es realmente un apuntador al primer elemento en el array, asi si a es
un arreglo adimensional entonces la direccin del primer elemento del array es &a[0] o
simplemente a.
La direccin del elemento i del array puede ser expresada como &a[i] o como a + i, por lo
tanto existen dos manera de escribir la direccin de cualquier elemento del array.
a[i] o *(a+i) representan el contenido que hay en la direccin en cuestin.
El nmero de bytes de memoria asociados con cada elemento del array depender del tipo de
dato empleado en la declaracin (1 byte para dados tipo char o 4 para datos tipo doubl por
ejemplo). La siguiente figura clarifica lo anterior:

Es posible acceder a cada uno de los elementos del arreglo por medio del ndice o de manera
alternativa usando apuntadores y es all donde entra en juego la aritmtica de punteros ya que por
medio de las operaciones de adicin y sustraccin nos podemos mover a las diferentes posiciones
del array para luego poder acceder a sus elementos. Para entender ms esto suponga que tiene la
siguiente porcin de cdigo:
int a[6]={1,0,4,7,8,10};
int i,suma = 0;
a[0]=2;
a[3]=10;
for(i = 1;i<6;i++) {
if(i%2==0) {
a[i] = -a[i];
}
else {
a[i]=a[i]+1;
}
}

Como se puede notar del cdigo anteriormente mostrado, el acceso al array fue haciendo uso de
subndices, a continuacin se muestra la versin alternativa haciendo uso de apuntadores:
int a[6]={1,0,4,7,8,10};
int *ptr; // Declaracion del apuntador
ptr = &a[0]; // Inicializacion del apuntador. (ptr = a)
*ptr = 2; // a[0] = 2
ptr = &a[3]; // Ahora ptr esta apuntando al elemento a[3]
*ptr=10; //a[3] = 10
ptr = &a[1]; // Ahora ptr esta apuntando al elemento a[1]
for(i = 1;i < 6;i++) {
if(i%2==0) {
*ptr = -(*ptr);
}
else {
*ptr = *ptr + 1;
}
ptr++; //Cambio del valor del apuntador para barrer
// el arreglo
}

Pregunta:
Con que valores queda el vector a tras la ejecucin del cdigo anteriormente mostrado?

El resultado de ejecutar los dos cdigos anteriormente mostrados es el mismo. Observe dos cosas:
Para barrer el array se modific el valor almacenado en el apuntador.
Para acceder a un elemento del array (ya sea para leer o para escribir) se desreferencio el
apuntador con el operador asterisco (*).

Dado el siguiente cdigo fuente:


// The swapf( ) function exchanges the values of two float variables.
// Arguments: Two pointers to float.

inline void swapf( float *p1, float *p2 );


{
float tmp = *p1; *p1 = *p2; *p2 = tmp; // Swap *p1 and *p2.
}
// The function selection_sortf( ) uses the selection-sort
// algorithm to sort an array of float elements.
// Arguments: An array of float, and its length.

void selection_sortf( float a[ ], int n ) // Sort an array a of n float


elements.
{
if ( n <= 1 ) return; // Nothing to sort.

float *last = a + n-1, // A pointer to the last element.


*p, // A pointer to a selected element.
*minPtr; // A pointer to the current minimum.

for ( ; a < last; ++a ) // Walk the pointer a through the array.
{
minPtr = a; // Find the smallest element
for ( p = a+1; p <= last; ++p ) // between a and the end of the array.
if ( *p < *minPtr )
minPtr = p;
swapf( a, minPtr ); // Swap the smallest element
} // with the element at a.
}

Qu es lo que hacen las funciones anteriormente mostradas?


Realice un programa en el cual pruebe las funciones anteriormente mostradas.

4.2.2 Apuntadores y arreglos multidimensionales

As como en el caso de los arreglos de una dimensin, es posible representar los arreglos
multidimensionales con una notacin de punteros equivalente.

En el caso de las matrices de dos dimensiones, cuando estas se almacenan en memoria, la forma
como la memoria se llena es fila por fila, es decir si se tiene una matriz de n filas por m columnas
las primeras n posiciones en memoria corresponden a los n elementos de la primera fila, las n
posiciones siguientes corresponden a los n elementos de la siguiente fila y as sucesivamente hasta
que todas las filas son ocupadas (n*m posiciones de memoria). La siguiente figura muestra esto:
Ahora bien, un arreglo de dos dimensiones puede ser tratado como un arreglo de una dimensin
cuyos elementos son arreglos de una dimensin (las filas) tal y como lo sugiere la siguiente figura:

Lo anterior hace posible que se pueda definir un arreglo de dos dimensiones como un apuntador a
un grupo de arreglos de una dimensin, de modo que una declaracin de un arreglo bidimensional
puede ser hecha de la siguiente manera:

T *(ptVar)[n];
Donde T est asociado al tipo de dato (el cual puede ser simple o compuesto) y n es el nmero de
filas del array bidimensional. La expresin anterior puede ser por lo tanto una alternativa a la
declaracin tpica de matrices por ejemplo para el caso de una matriz de n filas por n columnas
como la siguiente:

T mat[n][m];

La expresin anterior se puede generalizar a arreglos de ms elementos tal de modo que para una
matriz de dimensin N:

T mat[val1]...[val_N];

La expresin alternativa estar dada por:

T *(ptVar)[val_2][val_3]...[val_N];

Donde T se refiere al tipo de dato y las expresiones val_1, val_2, , val_N se refieren al nmero
mximo de elementos asociados con cada uno de los N subndices del array.

Otra cosa importante es la presencia del parntesis, este es necesario ya que si no est, no nos
estaramos refiriendo a un apuntador a un grupo de arrays sino a un array de apuntadores, esto
porque los [] tienen mayor precedencia que el *. As segn lo anterior:

int (*pz)[2]; // Crea un apuntador a un array de 2 enteros.


int *pax[2]; // Crea un array de dos punteros a enteros.

Ejemplo 1:
Se desea crear un array de bidimensional de 10 filas por 20 columnas llamado x esto puede ser
hecho, as:

int (*x)[20]; // Apuntador a un grupo de 20 enteros contiguos de


// un array unidimensional

O as:

int x[10][20];

El efecto se muestra en la siguiente figura:


Donde, x apunta al primer array de 20 elementos, el cual es la primera fila (fila 0), del array
original. De manera similar, (x + 1) apunta a los segundos 20 elementos del array (fila 1 del array
original) y as sucesivamente hasta la ultima fila.

Ejemplo 2:
Considere una matriz de tres dimensiones con la siguiente declaracin:

float t[10][20][30];

La declaracin alternativa usando apuntadores ser:

float (*t)[20][30];

En la declaracin anterior, se defini a t como un apuntador a un grupo de 20x30 elementos


contiguos de una matriz bidimensional. Por lo tanto segn lo anterior, t apuntara a los primeros
20x30 elementos, t +1 apuntara a los segundos 20x30 elementos y as sucesivamente.

4.2.3 Accediendo a los elementos de la matriz


Para acceder a un elemento particular dentro de un array particular se emplea el operador
indireccin (*). A continuacin se muestra como:

Ejemplo 3:
Supongase que se tiene un array entero de 10x20 y se desea acceder al elemento perteneciente a
la fila 2 y la columna 5 (x[2][5]) . La forma de acceso es la mostrada a continuacin:

*(*(x+2)+5);
Para acceder a dicho lugar de memoria es necesario tener en cuenta una serie de cosas:
x+2: Puntero al vector correspondiente a la fila 2.
*(x+2): Apuntador al primer elemento de la fila 2.
*(x+2)+5: Apuntador al elemento 5 en la fila 2.
*(*(x+2)+5): Elemento de la columna 5 y la fila 2, propiamente x[2][5].

Codifique el siguiente cdigo:

/* zippo2.c -- zippo infovia a pointer variable */


#include <stdio.h>
int main(void)
{
int zippo[4][2] = { {2,4} , {6,8} , {1,3} , {5, 7} };
int (*pz)[2];
pz = zippo;

printf(" pz = %p, pz + 1 = %p\n",


pz, pz + 1);
printf("pz[0] = %p, pz[0] + 1 = %p\n",
pz[0], pz[0] + 1);
printf(" *pz = %p, *pz + 1 = %p\n",
*pz, *pz + 1);
printf("pz[0][0] = %d\n", pz[0][0]);
printf(" *pz[0] = %d\n", *pz[0]);
printf(" **pz = %d\n", **pz);
printf(" pz[2][1] = %d\n", pz[2][1]);
printf("*(*(pz+2) + 1) = %d\n", *(*(pz+2) + 1));
return 0;
}
Preguntas:
Cul es la salida del programa anteriormente mostrado y por qu?

4.2.4 Arreglos de apuntadores


Un arreglo de apuntadores es un array cuyos elementos son apuntadores a algn tipo de dato.
Estos, constituyen una forma alternativa de expresar un arreglo multidimensional. Por ejemplo un
array de dos dimensiones:

T mat[val_1][val_2];

Puede ser reescrito como un array de apuntadores de la siguiente manera:

T *ptVar[val_1];

Luego, generalizando lo anterior para arreglos de N dimensiones tenemos que:

T *(ptVar)[val_2][val_3]...[val_N];

La forma alternativa ser:

T *(ptVar)[val_1][val_2]...[val_N-1];

Aqu T se refiere al tipo de dato y las expresiones val_1, val_2, , val_N se refieren al nmero
mximo de elementos asociados con cada uno de los N subndices del array. Note que a diferencia
del caso anterior ya no se emplean parntesis en este tipo de declaracin por lo que el array
contendr apuntadores al tipo especfico definido en la declaracin.

Ejemplo 1:
Supngase que se tiene una matriz bidimensional x de 10 filas por 20 columnas. Esta definida
como un vector de apuntadores sera:

int *x[10];

Aqu, x[0] apuntara al principio de la primera fila, x[1] al principio de la segunda, observe que a
diferencia del caso anterior no fue necesario declarar el nmero de elementos de cada columna
de manera explcita. La siguiente figura muestra el efecto de la anterior declaracin con ms
detalle:
Para acceder a un elemento individual del arreglo, tal como x[2][5] de la siguiente manera:

int *(x[2]+5);

Donde:
x[2]: Es un apuntador al primer elemento de la fila 2.
x[2] + 5: Es un apuntador al elemento 5 dentro de la fila 2.
*(x[2]+5): Se refiere al contenido del elemento de la fila 2 y la columna 5, es decir x[2][5].

Ejemplo 2:
Suponga que se tiene un array tridimensional de nmeros de punto flotante de dimensiones
10x20x30. La forma de expresar este array como un array de apuntadores bidimensional es:

float *t[10][20];

Lo cual genera un array de 200 apuntadores cada uno de los cuales esta apuntando a un vector
unidimensional. Ahora bien, si se desea acceder a un elemento individual tal como t[2][3][5], la
forma de accederlo es:

*(t[2][3]+5);
Los arreglos de apuntadores ofrecen a menudo un mtodo conveniente para almacenar cadenas
de caracteres. En esta situacin, cada elemento del array es un apuntador tipo carcter que indica
el principio de una cadena de caracteres separada, por lo tanto un array de n elementos puede
apuntar a diferentes cadenas de caracteres, de tal manera que cada cadena individual puede ser
referenciada por su correspondiente apuntador. La siguiente figura muestra este hecho:

La declaracin en C asociada para el caso ser:

char *myStrPtr[99] = {If anything can go wrong, it will,


Nothing is foolproof,
Every solution breeds new problems.};

Ahora si quisiera a la segunda frase para imprimirla entonces la instruccin seria:

cout << myStrPtr[1] << endl;

Tambien es posible pasar apuntadores a funciones pero eso no lo vamos a tratar en este caso.

4.3 Apuntadores a apuntadores


Es posible poner apuntar un apuntador a un apuntador, lo cual se indica con la cantidad de
asteriscos colocados en la declaracin del apuntador, as la declaracin realizada en las siguientes
lneas de cdigo:

char ch; /*Un caracter*/


char *pch; /*Un apuntado a un dato tipo caracter*/
char **pch; /*Un apuntador a un apuntador a un caracter*/

Tiene el efecto mostrado en la siguiente figura:


Cuando se inicializa un apuntador a un apuntador a este se le debe pasar la direccin de memoria
del apuntador al que est siendo inicializado, de modo que para obtener el efecto mostrado en la
siguiente figura:

Es necesario llevar a cabo las siguientes instrucciones:

pch = &ch; /*Inicializacion del apuntador*/


ppch = &pch; /*Inicializacion del apuntador al apuntador*/

La siguiente tabla muestra una lista de equivalencias entre los valores almacenados en las
variables anteriormente creadas:

tem Equivalencia en cdigo


Lugar de memoria accedido ( variable ch) ch = *pch = **ppch
Direccion de la variable ch (&ch) &ch = pch = *ppch
Direccion de memoria del apuntador (&pch) &pch = ppch
Direccion de memoria del apuntador al apuntador (&ppch) &ppch

La anterior tabla implica que si yo quiero cambiar el valor de ch lo puedo hacer ya modificando la
variable como tal o desreferenciando el apuntador que la apunta o desreferenciando el apuntador
del apuntador que la apunta, a continuacin se muestran las tres equivalencias:

ch = A; *pch = A; **ppch = A

Lo que se hizo anteriormente fue llevar directa o indirectamente el valor de la variable ch a A.

Ejercicio
Dado el siguiente cdigo fuente:

#include <iostream>

using namespace std;

int main() {
char *materias[3]={"Quimica","Matematicas","Fisica"};
float *notasMateria[3];
float **nota;
float nQuimica[]={2,4,5};
float nMatematicas[4]={3.2,1,2.2,5};
float nFisica[] = {4.5,4.3,3.2,1.5,5};
notasMateria[0]=nQuimica;
notasMateria[1]=&nMatematicas[0];
notasMateria[2]=nFisica;
return 0;
}
Preguntas:
Modifique el cdigo anterior de tal manera que pueda imprimir el valor que hay en cada uno
de los elementos del vector de apuntadores y llene la siguiente tabla:

Variable Valor
nQuimica
nFisica
nMatematicas
notasMateria[0]
notasMateria[1]
notasMateria[2]
&notasMateria[0]
&notasMateria[1]
&notasMateria[2]

De cunto es el tamao reservado por el compilador para una variable tipo float (recuerde el
operador sizeof)?
Cul es el efecto que se obtendra al ejecutar cada una de las siguientes instrucciones?, Si
alguna de estas genera error explique por qu?

Instruccin Comentario
nFisica[0]=3.0; Lleva al elemento 0 del array nFisica el valor de 3.
*(nMatematicas+2) = 3.5;
*(&nQuimica[2]-1) = 2.2;
*(notasMateria[2]+4)=0;
*(notasMateria+2)=0.5;
*(&notasMateria[1]+2)=0.5;

Dada la siguientes instrucciones cual es la forma equivalente de acceder desde el vector de


apuntadores notasMateria:

Instruccin Instruccion
nFisica[0]=3.0; *(notasMateria[0])=3.0;
nMatematicas[3]=0.7;
nQuimica[2]= nQuimica[0]+ nQuimica[1];
nMatematicas[3]=nQuimica[2];
nFisica[0]=(nFisica[1]+nFisica[2])/2;
nMatematicas[2]=4.8;

Es valida la siguiente instruccin?

nota = &notasMateria[2];

En caso de ser vlida qu es lo que hacer?, Cul es el valor de la variable nota?


Supongase que se aade al codigo anteriormente mostrado, las siguientes lneas de codigo,
que se hace en cada una de estas, Qu se modifica?

nota = &notasMateria[1];
cout << &notasMateria[1]<<" "<<&notasMateria[2]<<" "<<nota<<endl;
*nota += 2;
cout << &nMatematicas[2] << " " <<*nota << endl;
**nota = 0.7;

Referencias

C in an Nutshell.
C++ in a Nutshell.
Sam teach yourself C++ in 21 days.
Shaums outline of programming with C.
A introduction to design patterns in C with Qt4.
C primer plus.
http://docs.google.com/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnxjYXJsb3NobWVuZ
G96YWN8Z3g6MjFkZTI1MWJjYjM1ZWZmOA
http://www.virtual.unal.edu.co/cursos/ingenieria/2001839/modulo4/cap_05/leccion_3.htm
https://users.cs.jmu.edu/bernstdh/web/common/lectures/
http://computer.howstuffworks.com/c.htm
http://pw1.netcom.com/~tjensen/ptr/ch9x.htm
http://home.earthlink.net/~momotuk/pointers.pdf
http://www.lysator.liu.se/c/c-faq/c-2.html
http://www.cs.cf.ac.uk/Dave/C/node12.html#SECTION001210000000000000000
http://www.technoplaza.net/programming/lesson9p2.php
http://icesecurity.org/programacion/C/cursoc9.html
http://www.csse.monash.edu.au/~dwa/Animations/index.html
http://www.u-
gakugei.ac.jp/~miyadera/Education/TeachingSystem/Animations/LinkedList/linkedlist.html
http://www.macs.hw.ac.uk/~rjp/Coursewww/Cwww/linklist.html
http://www.ehow.com/how_2056292_create-linked-list-c.html
http://www.codeproject.com/KB/cpp/linked_list.aspx
http://cslibrary.stanford.edu/103/
http://www.codeproject.com/KB/cpp/PointerArticle.aspx
http://www.enm.bris.ac.uk/staff/pjn/EMAT10920/lesson10a.pdf
http://cplus.about.com/od/learning1/ss/pointers2.htm
http://www.sethi.org/classes/comp217/lab_notes/lab_10_pointers.html
http://www.cs.uregina.ca/Links/class-info/115/10-pointers/
http://cboard.cprogramming.com/c-programming/124384-advanced-pointer-use.html
http://computer.howstuffworks.com/c30.htm
http://www.technoplaza.net/programming/lesson9p2.php
http://www.cs.cf.ac.uk/Dave/C/node12.html
http://cplus.about.com/od/learningc/ss/pointers2_8.htm
http://cslibrary.stanford.edu/102/PointersAndMemory.pdf
http://publications.gbdirect.co.uk/c_book/chapter5/pointers.html
http://www.math.northwestern.edu/~wphooper/code/c/examples/pointers/
http://idlastro.gsfc.nasa.gov/idl_html_help/Pointer_Examples.html
http://augustcouncil.com/~tgibson/tutorial/ptr.html
http://cplus.about.com/od/learning1/ss/pointers.htm
http://cplus.about.com/od/learningc/ss/pointers_9.htm
http://icesecurity.org/programacion/C/cursoc22.html#arriba

S-ar putea să vă placă și