49
1 Ismael Camarero

¿Qué es un PUNTERO ?:

  • Upload
    colin

  • View
    61

  • Download
    4

Embed Size (px)

DESCRIPTION

¿Qué es un PUNTERO ?: Un puntero es un objeto que apunta a otro objeto. Es decir, una variable cuyo valor es la dirección de memoria de otra variable. No hay que confundir una dirección de memoria con el contenido de esa dirección de memoria. int x = 25;. - PowerPoint PPT Presentation

Citation preview

  • 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.No hay que confundir una direccin de memoria con el contenido de esa direccin de memoria. int x = 25;

    Direccin 1502 1504 1506 1508 La direccin de la variable x (&x) es 1502El contenido de la variable x es 25

    ......25............

    Ismael Camarero

  • Las direcciones de memoria dependen de la arquitectura del ordenador y de la gestin que el sistema operativo haga de ella. En lenguaje ensamblador se debe indicar numricamente la posicin fsica de memoria en que queremos almacenar un dato. De ah que este lenguaje dependa tanto de la mquina en la que se aplique. En C no debemos, ni podemos, indicar numricamente la direccin de memoria, si no que utilizamos una etiqueta que conocemos como variable (en su da definimos las variables como direcciones de memoria). Lo que nos interesa es almacenar un dato, y no la localizacin exacta de ese dato en memoria.

    Ismael Camarero

  • Una variable puntero se declara como todas las variables. Debe ser del mismo tipo que la variable apuntada. Su identificador va precedido de un asterisco (*): int *punt;Es una variable puntero que apunta a variable que contiene un dato de tipo entero llamada punt. char *car:Es un puntero a variable de tipo carcter. long float *num; float *mat[5]; // . . .Un puntero tiene su propia direccin de memoria: &punt&car

    Ismael Camarero

  • 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).Declaracin de variables puntero: Sea un fragmento de programa en C:

    char dato; //variable que almacenar un carcter. char *punt; //declaracin de puntero a carcter. punt = &dato; //en la variable punt guardamos la direccin // de memoria de la variable dato; punt apunta // a dato. Ambas son del mismo tipo, char.

    Ismael Camarero

  • int *punt = NULL, var = 14;punt = &var; printf(%#X, %#X, punt, &var) //la misma salida: direccinprintf(\n%d, %d, *punt, var); //salida: 14, 14 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).

  • Al trabajar con punteros se emplean dos operadores especficos: 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: *El operador * aplicado al nombre de un puntero indica el valor de la variable apuntada:float altura = 26.92, *apunta;apunta = &altura; //inicializacin del puntero

    Ismael Camarero

  • float altura = 26.92, *apunta;apunta = &altura; //inicializacin del puntero.printf(\n%f, altura); //salida 26.92.printf(\n%f, *apunta);No se debe confundir el operador * en la declaracin del puntero: int *p;Con el operador * en las instrucciones: . *p = 27; printf(\nContenido = %d, *p);

  • Veamos con un ejemplo en C la diferencia entre todos estos conceptos Veamos el archivo - punt0.cpp - punt1.cppEs decir: int x = 25, *pint; pint = &x;La variable pint contiene la direccin de memoria de la variable x. La expresin: *pint representa el valor de la variable (x) apuntada, es decir 25. La variable pint tambin tiene su propia direccin: &pint

    Ver sumpun.cpp

    Ismael Camarero

  • 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

  • p2 = &c; // Paso 7. La direccin de c es asignada a p2*p2 = 3; // Paso 8. c = 3printf("%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 = 1printf("%d %d %d\n", a, b, c); // Paso 13. Qu se imprime? }

    Ismael Camarero

  • Vamos a hacer un seguimiento de las direcciones de memoria y de los valores de las variables en cada paso. Suponemos que la variable a es colocada en la direccin 0000, b en la siguiente, es decir 0002, con un offset de 2 bytes, por ser valores integer. Se trata de un sistema de posiciones relativas de memoria. Se ver en aritmtica de punteros.Se obtiene el siguiente cuadro. En l reflejamos las direcciones relativas de memoria y los cambios en cada uno de los pasos marcados:

    Ismael Camarero

  • Pasoa 0000b0002c0004p10006p20008p00101000021000031000000024120000000251200020000610000200027100002000481030002000491030002000410103000200040006111030004000400061210100040004000613101000400040006

    Ismael Camarero

  • Inicializacin de punteros(I):

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

    < Almacenamiento > < Tipo > * < Nombre > = < Expresin >

  • 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

  • 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;

  • PUNTEROS Y ARRAYSSea 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

  • 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 1504 1506 1508 1510 1512 1514 Elemento mat[1] mat[2] mat[3] mat[4] mat[5] mat[6] mat[7]

    216-4292341203

    Ismael Camarero

  • Direccin 1502 1504 1506 1508 1510 1512 1514El 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:Elemento mat[1] mat[2] mat[3] mat[4] mat[5] mat[6] mat[7]

    216-4292341203

    Ismael Camarero

  • #include #include int mat[5]={2, 16, -4, 29, 234, 12, 0, 3}, i; //declaradas como globalesvoid 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

  • 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]

    216-4292341203

    Ismael Camarero

  • Analizando las direcciones de memoria del array: &mat[0] &mat[1] &mat[2] &mat[3] &mat[4] &mat[5] & mat[6] &mat[7]

    mat mat+1 mat+2 mat+3 mat+4 mat+5 mat+6 mat+7 Direccin del elemento 0Direccin del octavo elementoPuntero a la direccin del elemento 0Incremento en unaunidad int (dos bytes)mat++

    216-4292341203

    Ismael Camarero

  • 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
  • Ismael Camarero

  • Aritmtica de punteros (I):-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 NULLUna variable puntero puede ser restada o comparada con otra si ambas apuntan a elementos de un mismo array.

    Ismael Camarero

  • Aritmtica de punteros (II):- 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

  • Aritmtica de punteros (III):Observar las siguientes instrucciones: int *p; double *q; void *r; //puntero genrico 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 p = (int *)q; // legal

    Ismael Camarero

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

    *mat *(mat+1) *(mat+2) *(mat+4) *(mat+6)mat[0] = 2*(mat+3)*(mat+5)Empleamos el operador *, indireccin que nos da el contenido de la direccin de memoria apuntada.*mat = 2*(mat+7) = 3mat[7] = 3

    216-4292341203

  • Y... cmo se aplica la aritmtica de punteros para desplazarnos en un array bidimensional?: float mat[2][4]; //declaracin del arrayFila 0Fila 1 Col 0 Col 1 Col 2 Col 3Utilizando punteros, la declaracin ser: float (*mat)[4]; //array bidimensionalEn donde mat es un puntero a un grupo contiguo de arrays monodimensionales (vectores) de 4 elementos cada uno.

    1.45-23.5-14,0817.3202.950.0826.023

    Ismael Camarero

  • Existe, por tanto una equivalencia:Recordemos que *mat representa un puntero a la primera fila. A la segunda fila nos referimos mediante *(mat+1)+j para las direcciones y con *(*(mat+1)+j) para los contenidos. El segundo subndice actua sobre la columna.

    Con subndicesCon punterosValormat[0[[0]*(*(mat+0)+0)1.45mat[0[[1]*(*(mat+0)+1)-23.5mat[0[[2]*(*(mat+0)+2)-14.08mat[0[[3]*(*(mat+0)+3)17.3mat[1[[0]*(*(mat+1)+0)20mat[1[[2]*(*(mat+1)+1)2.95mat[1[[3]*(*(mat+1)+2)0.082mat[1[[4]*(*(mat+1)+3)6.023

  • 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). Ver dibujo:

    Ismael Camarero

  • 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)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[0][0] ; *(*(x+1)) x[1][0]*(*x+1) x[0][1]; **(x+1) x[1][0]Ver: ardepunt.cpp. pmatcon.cpp

  • 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 x y + z)) = 129; //asignacinSi 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 posicionesde memoria: array[1][1] fila 0 *(*(array+5)+1) fila 1 129 *(*array + 6)

  • PUNTEROS A ARRAYSUn 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 arraysVer pmatcon.cpp

    Ismael Camarero

  • Puntero a un grupo de arrays bidimensionalesEl array: int valor[x][y][z];Puede ser representado en la forma: int (*valor)[y][z];(*valor)[y][z](*(valor+1))[y][z]Sea el array valor[2][2][3]:(*valor)[1][2](*(valor+1)[1][1]Ver: ardepun.cpp

  • O como un ARRAY DE PUNTEROS: int *valor[x][y];

    sin parntesis En su nueva declaracin desaparecela ltima de sus dimensiones.Veamos ms declaraciones de arrays de punteros:int x[10][20]; int *x[10];float p[10][20][30]; int *p[10][20]; Array de 200 punteros, cada uno de los cuales apunta a un array de 30 elementos Ver ejemp11.cppejemp12.cpp

    Ismael Camarero

  • Punteros a CADENAS DE CARACTERES: 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*(nombre+2) direccin de memoria contenido

    PEPEPEREZ\0

  • nombre*(nombre+2)Si quiero recorrer la cadena con notacin de puntero: i = 0; do printf(%c, *(nombre+i); while(*(nombre+ i ++)); //postincremento Ver: pcad.cpp arraycad.cppCondicin de salida

    PEPEPEREZ\0

    Ismael Camarero

  • ARRAYS DE PUNTEROS A CADENAS DE CARACTERES:En un array de punteros a cadenas de caracteres cada elemento apunta a un carcter. La declaracin ser: char *cad[10]; //por ejemploGrficamente podra ser:cadcad+1 . . . . . .. . .cad[0]cad[4] . . .

    HOLA\0

    ADIOS\0

    Ismael Camarero

  • ARRAYS DE PUNTEROS A CADENAS DE CARACTERES: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

  • ARRAYS DE PUNTEROS A CADENAS DE CARACTERES: 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 inicioreserva...

    ............

    Ismael Camarero

  • OTRAS CLASES DE PUNTEROS:Punteros genricos: 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 Puntero 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;

  • OTRAS CLASES DE PUNTEROS:Punteros 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

  • OTRAS CLASES DE PUNTEROS: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. Ojo a los punteros locos.

    Ismael Camarero

  • OTRAS CLASES DE PUNTEROS:Punteros a datos complejos: Se pueden declara punteros a datos definidos por el usuario (typedef()), a datos struct, a funciones, como argumentos de funciones... Declaraciones complejas: Una declaracin compleja es un identificador con ms de de un operador. Para interpretar estas declaraciones hace falta saber que los corchetes y parntesis (operadores a la derecha del identificador tienen prioridad sobre los asteriscos (operadores a la izquierda del identificador. Los parntesis y corchetes tienen la misma prioridad y se evalan de izquierda a derecha. A la izquierda del todo el tipo de dato.Empleando parntesis se puede cambiar el orden de prioridades. Las expresiones entre parntesis se evalan primero, de ms internas a ms externas.

  • 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

  • Aplicando los puntos anteriores, podemos decir que char *(*(*var)( ))[10] 7 6 4 2 1 3 5 La interpretacin es:1. La variable var es declarada como2. un puntero a3. una funcin que devuelve4. un puntero a5. un array de 10 elementos, los cuales son 6. punteros a 7. objetos de tipo char.Para declaraciones de mayor complejidad, ver el archivo declarpunt.doc

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

    Ismael Camarero

  • Febrero-2001Todos los ejemplos estn editados en el compilador Borland C++ 3.1Comentarios, erratas... [email protected] que te haya sido til

    ytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue uytuytudeytuuytytue u