Está en la página 1de 51

Ismael Camarero

Qu es un PUNTERO?:
Un puntero es un objeto que apunta a otro objeto. Es decir,
una variable cuyo valor es la direccin de memoria de otra
variable.
Las direcciones de memoria dependen de la arquitectura
del ordenador y de la gestin que el sistema operativo haga
de ella.

Ismael Camarero

Qu es un PUNTERO?:
No hay que confundir una direccin de memoria con el
contenido de esa direccin de memoria.
int x = 25;
Direccin

...

...

1502

1504

1506

1508

25

...

...

...

...

La direccin de la variable x (&x) es 1502


El contenido de la variable x es 25

Ismael Camarero

Declaracin de variables puntero


Se declara como todas las variables y donde su
identificador va precedido de un asterisco (*):

int *punt;
punt Es una variable puntero a una variable de tipo entero.

char *car;

Un puntero
car Es un puntero a variable de tipo carcter.
tiene su
propia
long float *num;
direccin de
float *mat[5]; // . . .
memoria:
&punt
Ismael Camarero

&car

Declaracin de variables puntero


Es decir: hay tantos tipos de punteros como tipos de
datos, aunque tambin pueden declararse punteros a
estructuras ms complejas (funciones, struct, ficheros...) e
incluso punteros vacos (void ) y punteros nulos (NULL).
Ej.- Declaracin de variables puntero:
char dato;

//variable que almacenar un carcter.

char *punt;

//declaracin de puntero a carcter.

flotat *x;

//declaracin de puntero a real

Personas *y; //declaracin de puntero a estructura


FILE *z;

//declaracin de puntero a archivo


Ismael Camarero

Operadores de Punteros
Existen dos operadores :
Operador de direccin: & Representa la
direccin de memoria de la variable que le sigue:
&fnum representa la direccin de fnum.
Operador de contenido o indireccin: * Permite
acceder a la variable situada en la direccin de
memoria que se especifica en el operando.
*punt es el contenido del la direccion de punt
Ismael Camarero

Operadores de Punteros
Ejemplo de operadores:
float altura = 26.92, *apunta;
apunta = &altura; //inicializacin del puntero
printf(\n%f, altura);
//salida 26.92
printf(\n%f, *apunta); //salida 26.92
No se debe confundir el operador
del puntero:

int

Con el operador
.

*p;

* en la declaracin

* en las instrucciones:
*p = 27;

printf(\nContenido = %d, *p);


7

Operadores de Punteros
Veamos con un ejemplo en C la diferencia entre
todos estos conceptos
Veamos el archivo
- punt0.cpp , punt1.cpp, sumpun.cpp
Es decir:

int x = 25, *pint;


pint = &x;

pint apunta a la direccin de la variable x.


*pint es el valor de la variable (x), es decir 25.
pint tiene su propia direccin: &pint
Ismael Camarero

Operadores de Punteros
Veamos con otro ejemplo en C la diferencia entre
todos estos conceptos
void main(void) {
int a, b, c, *p1, *p2;
void *p;
p1 = &a;

// Paso 1. La direccin de a es asignada a p1

*p1 = 1;

// Paso 2. p1 (a) es igual a 1. Equivale a a = 1;

p2 = &b;

// Paso 3. La direccin de b es asignada a p2

*p2 = 2;

// Paso 4. p2 (b) es igual a 2. Equivale a b = 2;

p1 = p2;

// Paso 5. El valor del p1 = p2

*p1 = 0;

// Paso 6. b = 0

Operadores de Punteros
p2 = &c;

// Paso 7. La direccin de c es asignada a p2

*p2 = 3;

// Paso 8. c = 3

printf("%d %d %d\n", a, b, c);

// Paso 9. Qu se imprime?

p = &p1;

// Paso 10. p contiene la direccin de p1

*p = p2;

// Paso 11. p1= p2;

*p1 = 1;

// Paso 12. c = 1

printf("%d %d %d\n", a, b, c);

// Paso 13. Qu se imprime?

}
Ismael Camarero

10

Inicializacin de punteros(I):
< Almacenamiento > < Tipo >

* < Nombre > = < Expresin >

Si <Almacenamiento> es extern o static, <Expresion>


deber ser una expresin constante del tipo <Tipo>
expresado.
Si <Almacenamiento> es auto, entonces <Expresion> puede
ser cualquier expresin del <Tipo> especificado.
Ejemplos:
1) La constante entera 0, NULL (cero) proporciona un
puntero nulo a cualquier tipo de dato:
int *p;
p = NULL; //actualizacin

11

Inicializacin de punteros(II):
2) El nombre de un array de almacenamiento static o
extern se transforma segn la expresin:
a) float mat[12];
float *punt = mat;
b) float mat[12];
float *punt = &mat[0];
3) Un cast puntero a puntero:
int *punt = (int *) 123.456;
Inicializa el puntero con el entero.

Ismael Camarero

12

Inicializacin de punteros(III):
4) Un puntero a carcter puede inicializarse en la forma:
char *cadena = Esto es una cadena;
5) Se pueden sumar o restar valores enteros a las
direcciones de memoria en la forma: (aritmtica de
punteros)
static int x;
int *punt = &x+2, *p = &x-1;
6) Equivalencia: Dos tipos definidos como punteros a
objeto P y puntero a objeto Q son equivalentes slo si
P y Q son del mismo tipo. Aplicado a matrices:
nombre_puntero = nombre_matriz;

13

PUNTEROS Y ARRAYS
Sea el array de una dimensin:
int mat[ ] = {2, 16, -4, 29, 234, 12, 0, 3};
en el que cada elemento, por ser tipo int, ocupa dos bytes
de memoria.
Suponemos que la direccin de memoria del primer
elemento, es 1500:
&mat[0] es 1500
&mat[1] ser 1502
&mat[7] ser 1514
Ismael Camarero

14

PUNTEROS Y ARRAYS
PUNTEROS Y ARRAYS
int mat[ ] = {2, 16, -4, 29, 234, 12, 0, 3};
En total los 8 elementos ocupan 16 bytes.
Podemos representar las direcciones de memoria que
ocupan los elementos del array , los datos que contiene y
las posiciones del array en la forma:
Direccin 1502

16

1504

1506

1508

1510

1512

1514

-4

29

234

12

Elemento mat[1] mat[2] mat[3] mat[4] mat[5] mat[6] mat[7]


Ismael Camarero

15

PUNTEROS Y ARRAYS
Direccin

1502

1504

1506

1508

1510

1512

16

-4

29

234

12

1514

Elemento mat[1] mat[2] mat[3] mat[4] mat[5] mat[6] mat[7]


El acceso podemos hacerlo mediante el ndice:
x = mat[3]+mat[5]; // x = 29 + 12
para sumar los elementos de la cuarta y sexta posiciones.
Como hemos dicho que podemos acceder por posicin y
por direccin: Es lo mismo &mat[0] y mat?
Y &mat[1] = mat++ ?
Veamos el cdigo de un ejemplo:

Ismael Camarero

16

PUNTEROS Y ARRAYS

#include <stdio.h>

#include <conio.h>
int mat[5]={2, 16, -4, 29, 234, 12, 0, 3}, i; //declaradas como globales
void main() {
printf("\n%d", &mat[0]);

//resultado: 1500 (direccin de mem)

printf("\n%p", mat);

//resultado: 1500 ( " " " " " )

i++;

//i=1

printf("\n%p", mat+i);

//resultado: 1502 ( " " " " " )

printf("\n%d", *(mat+i));

//resultado: 16 (valor de mat[1] o valor

getch();

//en la direccin 1502

Ismael Camarero

17

PUNTEROS Y ARRAYS
Comprobamos con un ejemplo: dirmen.cpp

ejemplo

Parece deducirse que accedemos a los elementos del


array de dos formas:
- mediante el subndice.
- mediante su direccin de memoria.
Elemento mat[1] mat[2] mat[3] mat[4] mat[5] mat[6] mat[7]

16

-4

29

234

Ismael Camarero

12

3
18

Analizando las direcciones de memoria del array:


Direccin
del elemento
0

Direccin del
octavo elemento

&mat[0] &mat[1] &mat[2] &mat[3] &mat[4] &mat[5] & mat[6] &mat[7]

16

-4

29

mat

mat+1

mat+2

mat+3

Puntero a la
direccin del
elemento 0

234

12

mat+4 mat+5

Incremento en una
Ismael Camarero

unidad int (dos bytes)

mat+6

mat+7

mat++
19

PUNTEROS Y ARRAYS

De lo anterior se obtienen varias conclusiones:


- Es lo mismo &mat[0] que mat, &mat[2] que mat + 2
- Para pasar de un elemento al siguiente, es lo mismo:
for(i=0; i<8; i++)
printf(&mat [%d] = %p, i, &mat[i]);
que el cdigo:
for(i=0; i<8; i++)
printf(mat + %d = %p, i, mat + = i);
A esta forma de desplazarse en memoria se le llama
Aritmtica de punteros
Ismael Camarero

20

PUNTEROS Y ARRAYS

Ismael Camarero

21

Aritmtica de punteros
-A una variable puntero se le puede asignar la direccin de
cualquier objeto.
-A una variable puntero se le puede asignar la direccin de
otra variable puntero (siempre que las dos sealen el mismo
objeto)
-A un puntero se le puede inicializar con el valor NULL
-Una variable puntero puede ser restada o comparada con
otra si ambas apuntan a elementos de un mismo array.

Ismael Camarero

22

Aritmtica de punteros
Ejemplo:
int *punt = NULL, var = 14;
punt = &var;
Hay que tener cuidado con las direcciones apuntadas:
printf(%d, %d, *(punt+1), var+1);
*(punt + 1) repesenta el valor contenida en la direccin
de memoria aumentada en una posicin (int=2bytes), que
ser un valor no deseado. Sin embargo var+1 representa
el valor 15.
punt + 1 representa lo mismo que &var + 1 (avance en la
direccin de memoria de var).
23

Aritmtica de punteros
- Se puede sumar o restar valores enteros : p++, pv+3,
teniendo en cuenta que el desplazamiento (offset) depende
del tipo de dato apuntado:
p++;

//p apunta a la siguiente direccin

pv+=3 // pv apunta 3*n bytes del dato apuntado (offset)


Si tenemos:
float *decimal; //suponemos que apunta a 0000
decimal++;

//apunta a 0004

Ismael Camarero

24

Aritmtica de punteros

-Observar las siguientes instrucciones:


int*p;

double*q;
void*r;//punterogenrico
p=&34;//lasconstantesno
tienendireccin
p=&(i+1);//lasexpresionesno
tienendireccin
&i=p;//lasdireccionesnose
puedencambiar
Ismael Camarero

p=q;//ilegal

25

PUNTEROS Y ARRAYS

Utilizando la aritmtica de punteros nos desplazamos


de unas posiciones de memoria a otras. Pero. cmo acceder
a los contenidos de esas posiciones utilizando notacin de
punteros?
mat[0] = 2
mat[7] = 3
mat[0]

2
*mat

mat[1]

mat[2]

mat[3]

mat[4]

mat[5]

mat[6]

mat[7]

16

-4

29

234

12

*(mat+1) *(mat+2)
*mat = 2

*(mat+4)

*(mat+3)

*(mat+5)

*(mat+6)
*(mat+7) = 3

Empleamos el operador , indireccin que nos da


26
el contenido de la direccin de memoria apuntada.

PUNTEROS Y ARRAYS
Y... cmo se aplica la aritmtica de punteros para
desplazarnos en un array bidimensional?:
float mat[2][4];
//declaracin del array
Col 0
Col 1
Col 2
Col 3
Fila 0
Fila 1

1.45
20

-23.5
2.95

-14,08
0.082

17.3
6.023

Utilizando punteros, la declaracin ser:


float (*mat)[4]; //array bidimensional
En donde mat es un puntero a un grupo contiguo de arrays
monodimensionales (vectores) de 4 elementos cada uno.
Ismael Camarero

27

PUNTEROS Y ARRAYS
Existe, por tanto una equivalencia:
Con subndices

Con punteros

Valor

mat[0[[0]

*(*(mat+0)+0)

1.45

mat[0[[1]

*(*(mat+0)+1)

-23.5

mat[0[[2]

*(*(mat+0)+2)

-14.08

mat[0[[3]

*(*(mat+0)+3)

17.3

mat[1[[0]

*(*(mat+1)+0)

20

mat[1[[2]

*(*(mat+1)+1)

2.95

mat[1[[3]

*(*(mat+1)+2)

0.082

mat[1[[4]

*(*(mat+1)+3)

6.023

PUNTEROS Y ARRAYS
*mat representa un puntero a la primera fila.
*(mat+1)+j para las direcciones de elementos
*(*(mat+1)+j) para los contenidos.

Ismael Camarero

29

PUNTEROS Y ARRAYS
Si en
x[10][20] quiero acceder al elemento de la fila 3 y
la columna 6, lo hago escribiendo x[2][5]. Con notacin de
punteros, es equivalente a
* ( * ( x + 2 ) +5)
ya que x + 2 es un puntero a la fila 3. Por tanto. El
contenido de dicho puntero, *(x+2), es la fila 3. Si me
desplazo 5 posiciones en esa fila llego a la posicin
*(x+2)+5, cuyo contenido es *(*(x+2)+5).

Ismael Camarero

30

PUNTEROS Y ARRAYS
Si en
x[10][20] quiero acceder al elemento de la fila 3 y
la columna 6, lo hago escribiendo x[2][5]. Con notacin de
punteros, lo que hacemos es considerar que es un array
formado por 10 arrays unidimensionales (vectores) de 20
elementos cada uno, de modo que accedo a x[2][5] mediante
la expresin:
* ( * ( x + 2 ) +5)

Ver: ardepunt.cpp.

pmatcon.cpp

ya que x + 2 es un puntero a la fila 3. Por tanto. El


contenido de dicho puntero, *(x+2), es la fila 3. Si me
desplazo 5 posiciones en esa fila llego a la posicin
*(x+2)+5, cuyo contenido es *(*(x+2)+5). Las siguientes
expresiones con punteros son vlidas:
**x
*(*x+1)

x[0][0] ;
x[0][1];

*(*(x+1))

x[1][0]

**(x+1)

x[1][0]

31

PUNTEROS Y ARRAYS
Si en

int array[filas][columnas];

quiero acceder al elemento array[y][z] para asignarle un valor,


lo que el compilador hace es:
*(array +columnas * y + z)) = 129; //asignacin
Si fuera int array[2][5] y quisiera asignar 129 al elemento de
la fila 1 y columna 2, pondra:
*(array + 5x1 + 1)) = 129;
es decir, desde el origen del array avanza 6 posiciones

array[1][1]

de memoria:

fila 0

fila 1

129

*(*(array+5)+1)
*(*array + 6)

PUNTEROS Y ARRAYS
Un array multidimensional es, en realidad, una coleccin de
vectores. Segn esto, podemos definir un array
bidimensional como un puntero a un grupo contiguo de arrays
unidimensionales. Las declaraciones siguientes son
equivalentes:
int dat[fil][col]

int (*dat)[col]

En general:
tipo_dato nombre[dim1][dim2]. . . . .[dimp]; equivale a:
tipo_dato (*nombre)[dim2][dim3]. . . . .[dimp];
Puntero a un grupo de arrays
Ismael Camarero
Ver pmatcon.cpp

33

PUNTEROS Y ARRAYS
El array:

int valor[x][y][z];

Puede ser representado en la forma:


int (*valor)[y][z];

Ver: ardepun.cpp

Puntero a un grupo de arrays bidimensionales


Sea el array valor[2][2][3]:
(*valor)[y][z]

(*valor)[1][2]

(*(valor+1))[y][z]

(*(valor+1)[1][1]

PUNTEROS Y ARRAYS
O como un ARRAY DE PUNTEROS:
int *valor[x][y];
sin parntesis
En su nueva declaracin desaparece
la ltima de sus dimensiones.

Array de 200
punteros,
cada uno de
los cuales
apunta a un
array de 30
elementos

Veamos ms declaraciones de arrays


de punteros:
int x[10][20];

int *x[10];

float p[10][20][30];

int *p[10][20];
Ismael Camarero

Ver
ejemp11.cpp
ejemp12.cpp
35

Punteros a CADENAS
Una cadena de caracteres es un array de caracteres. La
forma de definir un puntero a una cadena de caracteres:
char *cadena;
El identificador del array es la direccin de comienzo del
array. Para saber dnde termina la cadena, el compilador
aade el carcter \0 (ASCII 0, NULL):
char *nombre = PEPE PEREZ;
nombre

direccin de memoria

P E P E
*(nombre+2)

P E R E Z \0
contenido

36

Punteros a CADENAS

nombre

P E P E

P E R E Z \0
*(nombre+2)

Si quiero recorrer la cadena con notacin de puntero:


i = 0;

Ver: pcad.cpp
arraycad.cpp

do
printf(%c, *(nombre+i);

while(*(nombre+ i ++)); //postincremento


Ismael Camarero

Condicin de
salida
37

Arrays de Punteros a CADENAS

En un array de punteros a cadenas de caracteres cada


elemento apunta a un carcter. La declaracin ser:
char *cad[10]; //por ejemplo
Grficamente podra ser:
cad[0]

...

H O L

cad
cad+1

...

A \0

cad[4]

A D I
...

Ismael Camarero

O S

\0

...
38

Arrays de Punteros a CADENAS


La declaracin:
char cad[10][80];
Reserva memoria para 10 cadenas de caracteres de80
caracteres cada una. Pero en la declaracin como array de
punteros:
char *cad[10];
el compilador desconoce el tamao de las cadenas: cunta
memoria reserva?
- si el array es static y se inicializan las cadenas en el propio
cdigo, el compilador calcula la dimensin no explicitada
(arrays sin dimensin explcita). Ver programa bornday.cpp
Ismael Camarero

39

Arrays de Punteros a CADENAS


- si las dimensiones no son conocidas, sabremos dnde
comienzan las cadenas, pero no dnde terminan. Para ello se
efecta la llamada reserva dinmica de memoria (funciones
malloc, calloc(), realloc() y free() de stdlib.h alloc.h):
char cad[10][80];
Equivale a

char **cad reservando 800 bytes

Ver programas ardinam1.cpp y ardinam2.cpp


inicio

reserva

... ...

...

... ...
Ismael Camarero

40

PUNTEROS A FUNCIONES:
Un puntero a funcin es una variable cuyos posibles
valores son direcciones en las que se encuentran
funciones.
La sintaxis de su definicin es la siguiente:
estilo nuevo:
tipo (*nombre)(tipo,... ,tipo)
estilo antiguo:
tipo (*nombre)(

);

Ismael Camarero

41

PUNTEROS A FUNCIONES:
La direccin de una funcin se obtiene con el nombre de la
funcin sin parntesis ni argumentos (no hace falta el operador
&): pf = nombre_funcin;
Si el puntero no apunta a ninguna funcin se inicializa a NULL:
pf = NULL;

Se puede realizar de dos maneras la invocacin de funciones


mediante punteros :
(*pf)( lista_parametros_actuales );
pf( lista_parametros_actuales );
Los punteros a funciones permiten pasar funciones como
parmetros en la llamada a otras funciones.
Ismael Camarero

42

PUNTEROS GENERICOS: Son tipo void:


void *generico;
Los punteros tipo void pueden apuntar a otro tipo de datos.
Es una operacin delicada que depende del tipo de
compilador. Es conveniente emplear el casting para la
conversin. An as, no todas las conversiones estn
permitidas. Ver programa: castpunt.cpp
PUNTEROS NULO: En C un puntero que apunte a un objeto
vlido nunca tendr un valor cero. El valor cero se utiliza
para indicar que ha ocurrido algn error (es decir, que
alguna operacin no se ha podido realizar)
int *p = NULL; //int *p=0;
43

PUNTEROS A CONSTANTES: Una declaracin de puntero


precedida de const hace que el objeto apuntado sea una
constante (aunque no el puntero):
const char *p = Valladolid;
p[0] = f //error. La cadena apuntada por + es cte.
p = Pucela //Ok. p apunta a otra cadena.
Si lo que queremos es declarar un puntero constante;
char *const p = Medina;
p[0] = s; //error: el objeto Medina, es cte.
p = Peafiel; //error: el puntero p es constante.
Ismael Camarero

44

PUNTEROS A PUNTEROS:
Ver ejemp4.cpp, ejemp11.cpp y ejemp12.cpp
int **puntero; //puntero a puntero a un objeto int.
El tipo de objeto apuntado despus de una doble indireccin
puede ser de cualquier clase.
Permite manejar arrays de mltiples dimensiones con
notaciones del tipo ***mat, de mltiple indireccin que
pueden generar problemas si el tratamiento no es el
adecuado.

Ismael Camarero

45

PUNTEROS A DATOS COMPLEJOS: Se pueden declara


punteros a datos definidos por el usuario (typedef()), a datos
struct, a funciones, como argumentos de funciones

46

DECLARACIONES COMPLEJAS:
Uno de los ms importantes defectos del lenguaje es la
dificultad de la comprensin de las declaraciones donde
intervienen simultneamente punteros, funciones y arrays
La regla general para interpretar una declaracin
compleja compuesta por funciones y punteros se basa en
la precedencia de los operadores *, () y [].
() y [] mayor precedencia, asociatividad ID
*
menor precedencia, asociatividad DI

Ismael Camarero

47

DECLARACIONES COMPLEJAS
Para interpretar declaraciones complejas podemos seguir el
orden:
1) Empezar con el identificador y ver si hacia la derecha hay
corchetes o parntesis.
2) Interpretar esos corchetes o parntesis y ver si hacia la
izquierda hay asteriscos.
3) Dentro de cada nivel de parntesis, de ms internos a ms
externos, aplicar puntos 1 y 2.
Veamos un ejemplo:

char *(*(*var)( ))[10]


Ismael Camarero

48

Aplicando los puntos anteriores, podemos decir que

char *(*(*var)( ))[10]


7

6 4 2 1

La interpretacin es:
1. La variable var es declarada como
2. un puntero a
3. una funcin que devuelve
4. un puntero a

5
Para declaraciones
de mayor
complejidad, ver el
archivo
declarpunt.doc

5. un array de 10 elementos, los cuales son


6. punteros a
7. objetos de tipo char.

49

DECLARACIONES COMPLEJAS
Para ver declaraciones de mayor complejidad, y su
significado, ver el documento de word:
declarpunt.doc

Ismael Camarero

50

Febrero-2001
Todos los ejemplos estn editados en el compilador
Borland C++ 3.1
Comentarios, erratas... icamarero98@hotmail.com
Deseo que te haya sido til

51