Sunteți pe pagina 1din 48

1

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.

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

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. Un puntero car Es un puntero a variable de tipo carcter. tiene su propia long float *num; direccin de float *mat[5]; // . . . memoria: &punt &car
4

char *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;
char *punt; flotat *x;

//variable que almacenar un carcter.


//declaracin de puntero a carcter. //declaracin de puntero a real

Personas *y; //declaracin de puntero a estructura FILE *z; //declaracin de puntero a archivo
5

Operadores de Punteros
Existen dos operadores : Operador de direccin: & Representa la direccin de memoria de la variable que le sigue: 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 &fnum representa la direccin de fnum.

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
7

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

*p;

* en la declaracin

Con el operador

* en las instrucciones: *p = 27;

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


8

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
9

Operadores de Punteros
p2 = &c; *p2 = 3; // Paso 7. La direccin de c es asignada a p2 // Paso 8. c = 3 // Paso 9. Qu se imprime?

printf("%d %d %d\n", a, b, c); p = &p1; *p = p2; *p1 = 1;

// Paso 10. p contiene la direccin de p1 // Paso 11. p1= p2; // Paso 12. c = 1 // Paso 13. Qu se imprime?

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

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.
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
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: Dir 1502 1504 1506 1508 1510 1512 1514

16

-4

29

234

12

Elemento mat[1]

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


15

PUNTEROS Y ARRAYS
Direccin 1502 1504 1506 1508 1510 1512 1514

16

-4

29

234

12

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:
16

#include <stdio.h>

PUNTEROS Y ARRAYS

#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]); printf("\n%p", mat); i++; printf("\n%p", mat+i); printf("\n%d", *(mat+i)); getch(); } //resultado: 1500 (direccin de mem) //resultado: 1500 ( " " " " " ) //i=1 //resultado: 1502 ( " " " " " ) //resultado: 16 (valor de mat[1] o valor //en la direccin 1502
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

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]

2
mat

16
mat+1

-4
mat+2

29
mat+3

234

12

0
mat+6

3
mat+7

mat+4 mat+5

Puntero a la direccin del elemento 0

Incremento en una unidad int (dos bytes)

mat++
19

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
20

PUNTEROS Y ARRAYS

PUNTEROS Y ARRAYS

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.

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++; Si tenemos: float *decimal; //suponemos que apunta a 0000 decimal++; //apunta a 0004 //p apunta a la siguiente direccin pv+=3 // pv apunta 3*n bytes del dato apuntado (offset)

24

-Observar las siguientes instrucciones: int *p; double *q; void *r; //puntero genrico

Aritmtica de punteros

p = &34; // las constantes no tienen direccin p = &(i+1); // las expresiones no tienen direccin &i = p; // las direcciones no se pueden cambiar p = q; // ilegal
25

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] mat[1] mat[2] mat[3] mat[4] mat[5] mat[6] mat[7]

PUNTEROS Y ARRAYS

2
*mat

16

-4

29
*(mat+3)

234
*(mat+4)

12
*(mat+5)

0
*(mat+6)

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

*(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.
27

PUNTEROS Y ARRAYS
Existe, por tanto una equivalencia: Con subndices
mat[0[[0] mat[0[[1] mat[0[[2] mat[0[[3] mat[1[[0] mat[1[[2] mat[1[[3] mat[1[[4]

Con punteros
*(*(mat+0)+0) *(*(mat+0)+1) *(*(mat+0)+2) *(*(mat+0)+3) *(*(mat+1)+0) *(*(mat+1)+1) *(*(mat+1)+2) *(*(mat+1)+3)

Valor
1.45 -23.5 -14.08 17.3 20 2.95 0.082 6.023

28

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.

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).

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) x[1][0] 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 de memoria: fila 0 fila 1 129 array[1][1] *(*(array+5)+1) *(*array + 6)

32

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] En general: tipo_dato nombre[dim1][dim2]. . . . .[dimp]; equivale a: tipo_dato (*nombre)[dim2][dim3]. . . . .[dimp]; Puntero a un grupo de arrays Ver pmatcon.cpp
33

int (*dat)[col]

PUNTEROS Y ARRAYS
El array: int valor[x][y][z]; int (*valor)[y][z]; Puede ser representado en la forma: 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)[1][1]
34

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

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. Veamos ms declaraciones de arrays de punteros: int x[10][20]; float p[10][20][30]; int *x[10]; int *p[10][20]; Ver ejemp11.cpp ejemp12.cpp
35

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

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

nombre

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

Si quiero recorrer la cadena con notacin de puntero: i = 0; do printf(%c, *(nombre+i); while(*(nombre+ i ++)); //postincremento Condicin de salida
37

Ver: pcad.cpp arraycad.cpp

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 cad+1 cad[0]

Arrays de Punteros a CADENAS

H O L

A \0

...

cad[4]

A D I
...

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
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 ...

... ...

... ...
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)( );

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.
42

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.

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.

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

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]


48

Aplicando los puntos anteriores, podemos decir que

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


7 6 4 2 1 3 5 Para declaraciones de mayor complejidad, ver el archivo declarpunt.doc La interpretacin es: 1. La variable var es declarada como 2. un puntero a 3. una funcin que devuelve 4. un puntero a 6. punteros a 7. objetos de tipo char.

5. un array de 10 elementos, los cuales son


49

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