You are on page 1of 11

1

Els punteros.
Un puntero siempre proporciona una direccin de memoria, puede, por ejemplo, guardar la
direccin de memoria de una variable, un array, una funcin. Trabajar con direcciones de memoria
facilita medios para acceder a datos que no estan disponibles de otras maneres. Por ejemplo,
modificar el valor de una variable local definida en una funcin desde otra funcin, como se ver
ms adelante.
Observe el siguiente programa, que a parte de ejemplo no sirve para nada ms.
#include <stdio.h>
#include <conio.h>
main()
{

int Var;
int *pVar;

// un puntero a int. Una variable para guardar la direccin de una


// variable tipo int

Var = 50;
pVar = &var // pVar guarda la direccin de memoria de var
*pVar = 30; // pone en direccin de memoria apuntada por pVar, o sea a var,
// el valor 30
printf(%d, Var); // escribir el valor 30
}
Suponga el siguiente mapa de memoria para el programa anterior.
Variable

Valor

Direccin

var

50

1004

pVar

1004

1008

La lnia var = 50, com ya sabe, guarda el valor 50 en la casilla de memoria var, que ocupa la
posicin de memoria 1004.
La lnia pVar = &var, guarda en la variable pVar la direccin de memoria ocupada per la variable
var, 1004. & se llama operador de indireccin, y sirve para indicar direccin de memoria de la
variable que precede.
La lnia *pVar = 30, guarda en la posicin de memoria apuntada por pVar (1004) el valor 30. Como
pVar guarda la direccin de memoria de var, lo que hace esta instruccin es cambiar el valor de la
variable var (le pone el valor 30).

Modificacin de los valores de las variables locales desde otra funcin.


Utilitzando punteros se pueden modificar los valores de les variables locales definidas en una
funci desde otra. Observe el programa siguiente, calcula el rea y el permetro de un
cuadrado.
#include <stdio.h>
#include <conio.h>
void calcular (int *parea , int *pperimetro, int Lon_costado);
main()
{
int area, perimetro, Lon_costado;
printf(Entre la longitud del costado : );
scanf(%d, &Lon_costado);
calcular(&area, & perimetre, Lon_costado);
printf(rea = %d, Permetro = %d , area, perimetro);
}
void calcular (int *parea, int *pperimetri, int Lon_Costado)
{
*pperimetro = Lon_Costado * 4;
*parea = Lon_costado * Lon_costado;
}
Linia calcular (&area, &perimetre, Lon_costado);
Observe que se pasan a la funcin calcula las direcciones de memoria de les variables area y
perimetro, y el valor de la variable Lon_costado. Es decir, en la funci calcula,

Variable local *parea = direccin de memoria de la variable local area declarada en


main.
Variable local *pperimetro = direccin de memoria de la variable local perimetro
declarada en main.
Variable local Lon_costado = valor de la variable local Lon_Costado declarada en
main.
La instruccin
*ppermetro = Lon_costado * 4;
Multiplica el valor de la variable Lon_costado por 4, y asigna este valor a la direccin de
memoria apuntada por pperimetro y que es la posicin ocupada por la variable local
perimetro de la funci main().
Cuidado, pperimetre y parea sn variables locales de la funcin calcular, NO son las
variable area y perimetro.

3
Entiende ahora la funcin scanf(%d, &var);
Vea este otro ejemplo. Hacer un programa para entrar dos valores desde el teclado y
guardarlos respectivamente en les variables A y B. Estos valores se han de pasar a una
funcin de manera que cuando se vuelva a main() se ha de cumplir que A > B.
#include <stdio.h>
#include <conio.h>
void cambiar (int *pA, int *pB);
main()
{
int A, B;
clrscr();
puts(Entre el valor para variable A : );
scanf(%d, &A);
puts(Entre el valor para la variable B : );
scanf(%d, &B);
cambiar(&A, &B);
printf(%d, %d , A, B);
}
void cambiar(int *pA, int *pB)
{
int Auxiliar;
if (*pB > *pA)
{
Auxiliar = *pA;
*pA = *pB;
*pB = Auxiliar;
}
}

Arrays y punteros.
Si recuerda el tema de arrays, y concretamente la seccin en la qual se habl del paso de
arrays a funciones, se dijo ( y despus se comprob), que cuando se pasa un array a una
funcin, se trabaja sobre el mismo array definido en la funci que llama, no sobre otro array.
Bien, entonces esto, como puede suponer, es porqu se pasa la direccin de memoria que
ocupa el array y no sus valors. Dado que un array es de hecho una variable que referencia una
direccin de memoria, se puede utilizar la notacin puntero para trabajar con arrays,
As por ejemplo, estas dos expressions son lo mismo,
nota[1] = 3; *(nota + 1);
De hecho, nota[1] es una notacin de puntero camuflada, cuando el compilador encuentra
esta sentencia, la traduce a la forma puntero; internamente la mquina no entiende los arrays
pero si los punteros.
Cuando se declara el array Notas[10], Notas no es nada ms que una referencia a una
direccin de memoria a partir de la cual se reserva el espacio suficiente para guardar diez
datos del tipo int. Vea el esquema siguiente:

Notas

1010

1010
1012
1014
1016
1018
1020

Observe como se han numerado las direcciones de dos en dos porqu los datos tipo int
ocupan dos bytes.
Como ya sabe, para referenciar los diferentes elementos de este array se ha de utilitza un
ndice cerrado entre las llaves [].
En el primer ejemplo para referenciar la variable Var a travs de su direccin, se ha hecho lo
siguiente:
pVar = &Var;
*pVar = 20;

// pVar guarda direccin de memoria de Var


// direccin de memoria apuntada por pVar = 20

Entonces, si Notas referencia una direccin de memoria, para guardar un valor en esta
direccin de memoria se puede utilizar la notacin:
*Notas = 10;
que seria lo mismo que
Notas[0] = 10;
Si se quiere guardar un valor en la segunda posicin del array , se ha de utilitza Notas[1] =
15, o bien
*(Notas + 1) = 15,
Esto es, en la siguiente posicin de memoria apuntada por Notas, poner un 15.
Observacin.
Siguiente posicin significa en este caso dos bytes ms all de posicin Notas, ya que un int
ocupa dos bytes; si el array fuera de datos tipo char, siguiente posicin significaria un byte
ms all; si fuese de datos tipo float, siguiente posicin significaria cuatro bytes ms all.
Recuerde que el nmero de bytes lo decide el compilador, en funcin del tipo de datos del
array.
Continuado con el array Notas, Notas[2] = 21; seria lo mismo que *(Notas+2) = 21, y se
interpretara como, dos posiciones de memoria, despus de Notas poner un 21.
Vea el esquema siguiente par comparar las notaciones array, y sus equivalentes notaciones
puntero.

Notas
Notas+1
Notas+2
Notas+3

10
15
21
43

Notas[0]
Notas[1]
Notas[2]
Notas[3]

Constantes puntero y variables puntero.


Para entrar valores en un array utilizaba el esquema siguiente:
for (y=0; y<10; y++)
scanf(%d, &Notas[y]);
Con la notacin puntero, esto seria:
for(y=0; y < 10; y++)
scanf(%d, (Notas + y));
Podra pensar entonces, en incrementar el puntero Notas y dejar el programa de la manera
siguiente:
for (y=0; y< 10; y++)
{
scanf(%d, Notas);
Notas++;
}
Esto pero, es incorrecto, Notas es una constante, No una variable, y a una constante no se le
puede cambiar el valor en todo el programa. Cuando se hace la declaracin int Notas[10] el
linkador fija una posicin de memoria apuntada por Notas para cuando se cargue el
programa. Esta posicin es fija, y no puede incrementarse; seria lo mismo que pretender
hacer c=5++;
S puede pero probar de hacer lo siguiente:
.
.
int Notas[10];
int *pNotas;
pNotas = Notas;
for(y=0; y< 10; y++)
{
scanf(%d, pNotas);
pNotes++;
}
pNotes es una variable puntero y por tanto se puede incrementar.

Punteros a arrays en funcions.


No le tendra que sorprender; para indicar que a una funcin se le pasa un array, se puede
utilizar la notacin puntero. As por ejemplo, en una funci par entrar datos en el array
Notas, se puede definir el parmetro de la manera siguiente:
void EntrarNotas(int *Notas)
que equivale a:
void EntrarNotas(int Notas[]);

Inicializacin de arrays con notacin puntero.


El lenguaje C, permite hacer asignaciones como las siguientes:
int Notas[]={10, 12, 21, 44, 56};
int *Notas = {10, 12, 21, 44, 56};
Inicia el array Notas con 5 elementos. En el primer caso, Notas es una constante puntero, en
el segundo caso, es una variable puntero.
char *Palabra=Hola;
Inicia la variable puntero Palabra con cinc carcters, los corresponents a Hola ms el \0 del
final.

Inicializar un array de punteros a cadena.


En uno de los programes de ejemplo visto en el tema de cadenas, se iniciaba un array de la
manera siguiente:
char Nombres[5][10] = { Pere,
Maria,
Llus,
Antoni,
Anna};
Tambin se puede iniciar un array de cadenas as:
char *Nombres[5] = {Pere,
Maria,
Llus,
Antoni,
Anna};
char *Nombres[5] significa array de 5 elementos del tipo puntero a char. Observe como
queda la memoria utilizando una declaracin u otra en el esquema siguiente:

char Nombres[5][10];
Nombres[0]
Nombres[1]
Nombres[2]
Nombres[3]
Nombres[4]

1000
1010
1020
1030
1040

P
M
L
A
A

e
a
l
n
n

r
r
u
t
n

e
i

o
a

\0
a
s
n
\0

\0
\o
I

\0

char *Nombres[5];
1000
1005
1011
1017
1023
Nombres[0]
Nombres[1]
Nombres[2]
Nombres[3]
Nombres[4]

P
M
L
A
A

e
a
l
n
n

r
r
u
t
n

e
y

o
a

\0
a
s
n
\0

\0
\0
y

\0

1000
1005
1011
1017
1023

Observe que en la versin de punteros no se utiliza tanta memoria. A la hora de manipular las
cadenes, tambin resulta ms prctico y rpido utilizar las referncias a las cadenas del array
de punteros. Por ejemplo, al ordenar un array es ms sencillo intercambiar los valors de los
punteros que no cambiar todos los caracteres que forman las cadenas. Resulta ms eficiente
intercanviar los punteros del primer y tercer elementos del array de punteros, que no mover
todos los caracteres de la primera cadena hacia la tercera. Vea el programa siguiente, que
ordena las cadenes, y observe el esquema para comprendre lo qu pasa.
#include <stdio.h>
#include <conio.h>
#include <string.h>
void Ordenar_Seleccion (char *Nombres[]);
main()
{
char *Nombres[5] = {Pere,Maria,Llus,Antoni,Anna};
int y;
Ordenar_Seleccin(Nombres);
for( y=0 ; y < 5 ; y++)
printf(%s \n , Nombres[y]);
}

8
void Ordenar_Seleccion(char *Nombres[])
{
char *pAux;
int y,k, posicin;

for (y=0; y< 5; y++)


{
*pAux = Noms[y]; // pAux apunta a posicin Nombres[y];
posicin = y;
for ( k = y+1; k < 5 ; k++)
{
if (strcmp(Nombres[k], pAux) > 0 )
{
pAux = Nombres[k];
posicin=k;
}
}
Nombres[posicin] = Nombres[y];
Nombres[y] = pAux;
}
Despus de la funcin Ordenar_Seleccin, el array Nombres quedaria:
1000
1005
1011
1017
1023

Nombres[0]
Nombres[1]
Nombres[2]
Nombres[3]
Nombres[4]

P
M
L
A
A

e
a
l
n
n

r
r
u
t
n

e
y

o
a

\0
a
s
n
\0

\0
\0
i

\0

1000
1005
1011
1017
1023

Punteros a Punteros. Doble indireccin.


El lenguaje de programacin C permite referenciar un puntero con otro puntero. Son
declaracions ciertamente complejas, que algunas veces la notacin C las hace todavia ms
difciles de interpretar. Por ejemplo, una declaracin como la siguiente:
int **ppInt;
es un puntero a un puntero que apunta a un puntero que apunta a un dato del tipo int. Vea el
siguiente fragmento de cdigo:
int var;
int *pVar;
int **ppVar;

// Puntero a posicin de memoria ocupada por un int


// Puntero a posicin de memoria ocupada por un puntero a int.

Var = 10;
*pVar = Var;

// pVar guarda la direccin de memoria de variable Var

*pVar = 20; // Direccin de memoria apuntada por pVar (variable Var), poner un 20
printf(%d, Var);

// Imprimir 20;

*ppVar = &pVar; // ppVar guarda direccin de memoria de variable pVar


**ppVar = 30;

// en la direccin de memoria que apunta la variable que hay


// en la direccin apuntada per ppVar (variable pVar), poner
// un 30

printf(%d, Var);

// Imprimir un 30

Es realmente rebuscado, pero hay situaciones (es posible que nunca las encuentre, y si
encuentra una desear no haberla encontrado) que slo pueden resolverse utilizando este tipo
de notacin.
Vea a continuacin un ejemplo de utilizacin de punteros a punteros, Los arrays
bidimensionales.
Primeramente recuerde que un array bidimensional no es ms que un array de arrays.
Suponga un array de int declarado como sigue:
int Tabla[5][5];
1
6
11
16
21

2
7
12
17
22

3
8
13
18
23

4
9
14
19
24

5
10
15
20
25

Tabla[5][5], significa un array formado por 5 arrays, cada uno de ellos con 5 datos del tipo
int..
Tabla[0]

Tabla[1]

10

Tabla[2]

11

12

13

14

15

Tabla[3]

16

17

18

19

20

Tabla[4]

21

22

23

24

25

Tabla es la direccin de todo el array, supoga que comienza en la direccin 1000. En un array
de enteros cada elemento ocupa dos bytes, cada fila entonces, empezar 10 bytes despus de
la anterior (5 elementos de cada fila por dos bytes que tiene cada elemento). El compilador
sabe cuantas columnas tiene cada fila del array ya que se le ha indicado en la declaracin.
As, Tabla+1 es la direccin de tabla 1000, ms los bytes que ocupa una fila, 10; Tabla+1
comenzar entonces en la direccin 1010, Tabla+2 en la direccin 1020, Tabla+3 en la
direccin 1040, y Tabla+5 en la direccin 1050.

Ahora que ha visto como referenciar cada una de las filas; vea como se referencia con
notacin puntero, un elemento individual de alguna de las filas.

10
Cogeremos por ejemplo el primer elemento de la segunda fila. Con notacin array la
direccin de este elemento se indica con &Tabla[1][0], con notacin puntero se indica con
*(Tabla+1). Observe que tanto Tabla+1 como *(Tabla+1) hacen referencia a la misma
direccin. Si se suma 1 a Tabla+1, se aaden 10 bytes, y se encuentra Tabla+2, la direccin
del primer elemento de la tercera fila, pero si se suma 1 a *(Tabla+1), se est sumando slo
dos bytes encontrando entonces la direccin del segundo elemento de la segunda fila. La
expresin quedaria *(Tabla+2)+1, y para referenciar el contenido de esta direccin slo hace
falta referenciar con notacin puntero la expresin anterior, o sea Tabla[1][1] =
*(*(Tabla+1)+1). Generalizando :
Tabla[y][j] = *(*(Tabla+y)+j)
Vuelva a leer el apartado anterior y resiga el esquema siguiente:
Tabla
Tabla+1
*(Tabla+1)
*(*(Tabla+1)+1)

1000
1

1002
2

1004
3

1006
4

1008
5

1010
6
1020
11
1030
16
1040
21

1012
7
1022
12
1032
17
1042
22

1014
8
1024
13
1034
18
1044
23

1016
9
1026
14
1036
19
1046
24

1018
10
1028
15
1038
20
1048
25

Punteros a estructuras.
Un puntero a una estructura se declara de la manera siguiente:
struct Alguna_Cosa *pAlguna_Cosa;
Per referenciar una estructura a travs dun puntero ho farem de la manera siguiente:
struct Alumno
{
char Nombre[10];
int Nota;
int Edat;
};
.
.
struct Alumno Estudiante;
struct Alumne *pAlumno;
pAlumno = &Estudiante;// pAlumno apunta a la variable estudiante.
.
.

11
Ya sabemos que para referenciar los diferentes elementos de la estructura se ha de utilizar la
notacin punto,
Estudiante.Nombre
Estudiante.Nota
Estudiante.Edat
Si se quiere utilizar el puntero, no se puede utilizar la notacin punto, pAlumne no es una
estructura, es un puntero a una estructura, y el operador punto requiere una estructura a su
izquierda. Dado que ya sabe que pAlumno apunta a Estudiante, antonces *pAlumno es el
contenido de Estudiante, por tanto, puede referenciar los elementos de la variable Estudiante
de la manera siguiente:
(*pAlumne).Nombres
(*pAlumne).Edat
(*pAlumne).Nota
Ha de utilizar los parntesi para que el operador punto tenga prioridad los otros. Esta
expresi apenas se utiliza ya que C proporciona una expressin ms simple, el operador ->,
una combinaci del signo menos, y el signo menor que, llamado operador flecha. As , para
referenciar los elementos de una estructura a travs de un puntero se ha de escribir de la
manera siguiente:
pAlumne->Nombres
pAlumne->Edat
pAlumne->Nota
Observe el programa siguiente:
#include <stdio.h>
#include <conio.h>
struct Alumno
{
char Nombre[10];
int Edat;
int Nota;
};
main()
{

struct Alumno Estudiante;


struct Alumno *pAlumno;
pAlumno = &Estudiante;
puts(Nombres : );
gets(pAlumno->Nombre);
puts(Edat : );
scanf(%d , pAlumno->Edad);
puts(Nota : );
scanf(%d , pAlumno->Nota);

You might also like