Sei sulla pagina 1di 19

UNIVERSIDAD AUTONOMA DE CIUDAD JUAREZ INSTITUTO DE INGENERIA Y TECNOLOGIA

TEMA: INVESTIGACION BIBLOGRAFICA #6 APUNTADORES


Integrantes: Manuel Arredondo Ramos 104000 Edgar Martnez Guerra 105564 Equipo:8 GRUPO:C

PROGRAMACION DE COMPUTADORAS 1
Investigacin
25/OCTUBRE/2011

INDICE
Qu es un apuntador?....................................................................................................3 Introduccin a los apuntadores....3 Declaracin de apuntadores.3 Diferencia entre "*" y "&"4 Apuntadores y Funciones..5 Referencia de apuntadores/ Asignacin de valores.6 Aritmtica de apuntadores.7 Apuntadores y estructuras.8 Concepto y aplicaciones de la Doble Indireccin.9 Apuntadores a apuntadores.10 Aritmtica de apuntadores12 Arreglos multidimensionales y apuntadores.13 Arreglos de apuntadores.15 Apuntadores a funciones.16 Biblografia.19

Qu es un apuntador?
Los punteros o tambin llamados aputadores permiten simular el paso por referencia, crear y manipular estructuras dinamicas de datos, tales como listas encadenadas, pilas, colas y rboles. Generalmente las variables contienen valores especificos. Los punteros son variables pero en vez de contener un valor especifico, contienen las direcciones de las variables a las que apuntan. Para obtener o modificar el valor de la variable a la que apuntan se utiliza el operador de indireccin. Los punteros, al ser variables deben ser declaradas como punteros antes de ser utilizadas.

Introduccin a los apuntadores


Los apuntadores son variables que guardan direcciones en C . Proporcionan mucha utilidad al programador para accesar y manipular datos de maneras que no es posible en otros lenguajes. Tambien son utiles para pasarle parametros a las funciones de tal modo que les permiten modificar y regresar valores a la rutina que las llama. Cuando se utilizan incorrectamente, son tambin fuente tanto de fallas en el programa como de frustracin para el programador.

Declaracin de apuntadores Para declarar un apuntador se especica el tipo de dato al que apunta, el operador *, y el nombre de la puntador. La sintaxis es la siguiente: <tipo de dato apuntado> *<indenticador del apuntador> A continuacion se muestran varios ejemplos: int *ptr1; // Apuntador a un dato de tipo entero (int) char *cad1, *cad2; // Dos apuntadores a datos de tipo caracter (char) float *ptr2; // Apuntador a un dato de tipo punto-flotante (float) Un programa esta corriendo todas las variables se guardan en memoria, cada una tiene su direccin o localidad nica. Generalmente, una variable y su localidad asociada contienen valores. Por ejemplo, cuando declaras: int count = 5; El valor "5" se guarda en memoria y puede ser accesado usando la variable "count". Un apuntador es un tipo especial de variable que contiene una direccin de memoria en
3

lugar del valor de un dato. Tal como un dato es modificado cuando una variable normal es usada, el valor de la direccin guardado en el apuntador cambia cuando este es manipulado.

Generalmente, la direccin guardada en el apuntador es la direccin de alguna otra variable. int *ptr; ptr = &count /* Guarda la direccin de count en ptr */ /* El operador unario & regresa la direccin de una variable */ Para obtener el valor que esta guardado en la localidad de memoria del apuntador es necesario referenciar el apuntador. La referencia se hace con el operador unario "*". int total; total = *ptr; /* El valor de la direccipon guardada en ptr es asignada a total */ La mejor manera de aprender a usar apuntadores es con ejemplos. Hay ejemplos de los tipos de operaciones ya discutidas abajo. Los apuntadores son un tema dificil. No te preocupes si todava no queda todo claro. Diferencia entre "*" y "&" En C, al contrario que en otros lenguajes de programacion, se puede obtener directamente la direccion de memoria de cualquier variable. Esto es posible hacerlo con el operador unario "&"; asi: char a; /* Variable 'a' de tipo char */

printf("la direccion de memoria de 'a' es: %p \n", &a); y para obtener lo apuntado por un puntero se utiliza el operador unario "*" de esta forma: char a; /* Variable 'a' de tipo char */

char *pchar; /* Puntero a char 'pchar' */ pchar = &a; /* 'pchar' <- @ de 'a' */ printf("la direccion de memoria de 'a' es: %p \n", &a);
4

printf("y su contenido es : %c \n", *pchar); Uno de los casos mas comunes donde se ve la relacion entre estos dos operadores es la declaracion y utilizacion de funciones: void Funcion ( int *int_pointer ) /*Paso de una variable de tipo entero por REFERENCIA */ /* equivalente en Modula 2: PROCEDURE Funcion ( VAR a:INTEGER ) */ int a; a=6; Funcion ( &a ); /* ya que la declaracion de la funcion pide la direccion de una variable de tipo entero */

Apuntadores y Funciones Cuando C pasa argumentos a funciones, los pasa por valor, es decir, si el parmetro es modificado dentro de la funcin, una vez que termina la funcin el valor pasado de la variable permanece inalterado. Hay muchos casos que se quiere alterar el argumento pasado a la funcin y recibir el nuevo valor una vez que la funcin ha terminado. Para hacer lo anterior se debe usar una llamada por referencia, en C se puede simular pasando un puntero al argumento. Con esto se provoca que la computadora pase la direccin del argumento a la funcin. Para entender mejor lo anterior consideremos la funcin swap() que intercambia el valor de dos argumentos enteros: void swap(int *px, int *py); main() { int x, y; x = 10; y = 20; printf("x=%d\ty=%d\n",x,y);
5

swap(&x, &y); printf("x=%d\ty=%d\n",x,y); } void swap(int *px, int *py) { int temp; temp = *px; /* guarda el valor de la direccion x */ *px = *py; /* pone y en x */

*py = temp; /* pone x en y */ } Referencia de apuntadores/ Asignacin de valores La referencia permite manipular los datos contenidos en la direccin de memoria guardada en el apuntador. El apuntador guarda una direccin de memoria. La referencia permite que los datos en esa direccin de memoria sean modificados. El operador unario "*" se usa para la referencia. Por ejemplo: *pt1 =*pt1 + 2; Esto le aade dos al valor "apuntado por" pt1. Esto quiere decir que esta instruccin le suma 2 al contenido de la direccin de memoria guardada en el apuntador pt1. As, en el programa main, pt1 contiene la direccin de j. La variable "j" fue inicializada en 1. El efecto del cdigo de arriba es sumar 2 a j. El contenido de las direcciones guardadas en un apuntador pueden ser asignadas a otro apuntador o variable. *pt2 = *pt1; /* asigna el contenido de la memoria apuntada por pt1 */ /* al contenido de la memoria apuntada por pt2 */ k = *pt2; /* asigna el contenido del apuntador pt2 por dos a k */

Aritmtica de apuntadores Parte del poder de los apuntadores viene de la habilidad de realizar operaciones matemticas sobre los mismos apuntadores. Los apuntadores pueden ser incrementados, decrementados y manipulados usando expresiones matemticas. Recordando el apuntador flotante "pt3" y el arreglo flotante "values" declarados en el programa main de arriba. pt3 = &values[0]; /* La direccin del primer elemento de "values" se guarda en pt3*/ pt3++; /* pt3 ahora contiene la direccin del segundo elemento de values */ *pt3 = 3.1415927; /* El segundo elemento de values tiene pay (de hecho pi)*/ pt3 += 25; /* pt3 ahora apunta al elemento 27 de values */ *pt3 = 2.22222; /* el elemento 27 de values ahora es 2.22222 */ pt3 = values; /*pt3 apunta al primer elemento de values, ahora */ for (ii = 0; ii < 100; ii++) { *pt3++ = 37.0; /* esto pone todo el arreglo en 37.0 */ } pt3 = &values[0]; /* pt3 contiene la direccin del primer elemento de values */ pt4 = &results[0]; /* pt4 contiene la direccin del primer elemento de results */ for (ii=0; ii < 100; ii++)
7

{ *pt4 = *pt3; /* Los contenidos de las direcciones de pt3 se le asignan a los contenidos de las direcciones de pt4 */ pt4++; pt3++; } Apuntadores y estructuras Los apuntadores a estructuras se definen fcilmente y en una forma directa. Considerar lo siguiente: main() { struct COORD { float x,y,z; } punto; struct COORD *ap_punto; punto.x = punto.y = punto.z = 1; ap_punto = &punto; /* Se asigna punto al apuntador */ ap_punto->x++; ap_punto->y+=2; ap_punto->z=3; } Otro ejemplo son las listas ligadas: typedef struct { int valor; struct ELEMENTO *sig; } ELEMENTO; /* Con el operador -> se accesan los miembros */ /* de la estructura apuntados por ap_punto */

ELEMENTO n1, n2; n1.sig = &n2; Nota: Solamente se puede declarar sig como un apuntador tipo ELEMENTO. No se puede tener un elemento del tipo variable ya que esto generara una definicin recursiva la cual no esta permitida. Se permite poner una referencia a un apuntador ya que los los bytes se dejan de lado para cualquier apuntador.

Concepto y aplicaciones de la Doble Indireccin. Un puntero es una variable como las dems de C. Ahora bien, toda variable posee su direccin, luego los punteros tambin tienen direccin (la suya, no la que contienen). Esta direccin se puede almacenar en variables que son igualmente punteros, y cuya declaracin es como puede verse en el ejemplo siguiente: Tipo_base variable; Tipo_base * ptb = &variable; Tipo_base ** pptb = &ptb; El doble asterisco indica que pptbes un "doble puntero" o ms exactamente el puntero de un puntero. Entonces se tienen los resultados esperables al aplicar el operador *, que deshace (una) indireccin: *pptb equivale a ptb **pptb equivale a variable

Estas equivalencias son sumamente importantes: dado el puntero de un puntero, se puede modificar el puntero, del mismo modo que dado el puntero de una variable se puede modificar la variable. Adems, como se recordar, todo puntero (y los dobles punteros son punteros, no hay que olvidarlo) se puede complementar con un ndice, y el puntero en cuestin pasa a comportarse como si fuese una lista monodimensional, formada por elementos del tipo base. Esto va a tener dos consecuencias importantes, que sern de aplicacin en muchos programas: En la seccin dedicada a funciones se estudian los conceptos de paso por valor y paso por referencia. En C, todos los parmetros reales sin excepcin pasan por valor. En particular, todos los parmetros que sean punteros pasarn por valor (aunque las variables que sealan pasen por referencia). Esto plantea un problema: si se pasa un
9

puntero como parmetro, el valor del parmetro real pasa por valor y por tanto no es modificable desde el interior de la funcin. Esto puede ser grave para funciones que reciban un puntero de valor NULL y deseen reservar memoria dinmica internamente, devolviendo a travs del puntero recibido la direccin del bloque reservado. Ahora bien, si se pasa un doble puntero como parmetro real, entonces el doble puntero pasa por valor... pero el puntero que seala pasa por referencia! Esto abre la puerta para modificar punteros desde el interior de una funcin; basta pasarlos como doble puntero (esto es, basta pasar la direccin del puntero que se quiere modificar). Un puntero es una variable como otra cualquiera, y si se quiere que pase a una funcin por referencia, debe pasarse a esa funcin la direccin del puntero (que es, decimos, un doble puntero).

Apuntadores a apuntadores Un arreglo de apuntadores es lo mismo que apuntadores a apuntadores. El concepto de arreglos de apuntadores es directo ya que el arreglo mantiene su significado claro. Sin embargo, se pueden confundir los apuntadores a apuntadores. Un apuntador a un apuntador es una forma de direccionamiento indirecto mltiple, o una cadena de apuntadores. Como se ve en la figura 10.1, en el caso de un apuntador normal, el valor del apuntador es la direccin de la variable que contiene el valor deseado. En el caso de un apuntador a un apuntador, el primer apuntador contiene la direccin del segundo apuntador, que apunta a la variable que contiene el valor deseado. Se puede llevar direccionamiento indirecto mltiple a cualquier extensin deseada, pero hay pocos casos donde ms de un apuntador a un apuntador sea necesario, o incluso bueno de usar. La direccin indirecta en exceso es difcil de seguir y propensa a errores conceptuales. Se puede tener un apuntador a otro apuntador de cualquier tipo. Considere el siguiente cdigo: main() { char ch; /* Un caracter */

char *pch; /* Un apuntador a caracter */ char **ppch; /* Un apuntador a un apuntador a caracter */

ch = 'A';
10

pch = &ch; ppch = &pch; printf("%c\n", **ppch); /* muestra el valor de ch */ } Lo anterior se puede visualizar como se muestra en la figura , en donde se observa que **ppch se refiere a la direccin de memoria de *pch, la cual a su vez se refiere a la direccin de memoria de la variable ch. Pero qu significa lo anterior en la prctica?

La figura es apuntador a un apuntador, y apuntador a un char . Se debe recordar que char * se refiere a una cadena la cual termina con un nulo. Por lo tanto, un uso comn y conveniente es declarar un apuntador a un apuntador, y el apuntador a una cadena, ver en la figura.

En la figura el apuntador a un apuntador, y apuntador a una cadena. Tomando un paso ms all lo anterior, se pueden tener varias cadenas apuntadas por el apuntador, ver figura

11

En la figura se ve el apuntador a varias cadenas. Se pueden hacer referencias a cadenas individuales mediante ppch[0], ppch[1], .... Esto es idntico a haber declarado char *ppch[].

Aritmtica de apuntadores Parte del poder de los apuntadores viene de la habilidad de realizar operaciones matemticas sobre los mismos apuntadores. Los apuntadores pueden ser incrementados, decrementados y manipulados usando expresiones matemticas. Recordando el apuntador flotante "pt3" y el arreglo flotante "values" declarados en el programa main de arriba.

pt3 = &values[0]; /* La direccin del primer elemento de "values" se guarda en pt3*/ pt3++; /* pt3 ahora contiene la direccin del segundo elemento de values */ *pt3 = 3.1415927; /* El segundo elemento de values tiene pay (de hecho pi)*/ pt3 += 25; /* pt3 ahora apunta al elemento 27 de values */ *pt3 = 2.22222; /* el elemento 27 de values ahora es 2.22222 */ pt3 = values; /*pt3 apunta al primer elemento de values, ahora */ for (ii = 0; ii < 100; ii++) { *pt3++ = 37.0; /* esto pone todo el arreglo en 37.0 */ }
12

pt3 = &values[0]; /* pt3 contiene la direccin del primer elemento de values */ pt4 = &results[0]; /* pt4 contiene la direccin del primer elemento de results */ for (ii=0; ii < 100; ii++) { *pt4 = *pt3; /* Los contenidos de las direcciones de pt3 se le asignan a los contenidos de las direcciones de pt4 */ pt4++; pt3++; }

Arreglos multidimensionales y apuntadores Un arreglo multidimensional puede ser visto en varias formas en C, por ejemplo: Un arreglo de dos dimensiones es un arreglo de una dimensin, donde cada uno de los elementos es en s mismo un arreglo. Por lo tanto, la notacin a[n][m] nos indica que los elementos del arreglo estn guardados rengln por rengln. Cuando se pasa una arreglo bidimensional a una funcin se debe especificar el nmero de columnas -- el nmero de renglones es irrelevante. La razn de lo anterior, es nuevamente los apuntadores. C requiere conocer cuantas son las columnas para que pueda brincar de rengln en rengln en la memoria. Considerando que una funcin deba recibir int a[5][35], se puede declarar el argumento de la funcin como: f( int a[][35] ) { ..... } o an f( int (*a)[35] ) { ..... }

13

En el ltimo ejemplo se requieren los parnteis (*a) ya que [ ] tiene una precedencia ms alta que *. Por lo tanto: int (*a)[35]; declara un apuntador a un arreglo de 35 enteros, y por ejemplo si hacemos la siguiente referencia a+2, nos estaremos refiriendo a la direccin del primer elemento que se encuentran en el tercer rengln de la matriz supuesta, mientras que int *a[35]; declara un arreglo de 35 apuntadores a enteros. Ahora veamos la diferencia (sutil) entre apuntadores y arreglos. El manejo de cadenas es una aplicacin comn de esto. Considera: char *nomb[10]; char anomb[10][20]; En donde es vlido hacer nomb[3][4] y anomb[3][4] en C. Sin embargo: anomb es un arreglo verdadero de 200 elementos de dos dimensiones tipo char. El acceso de los elementos anomb en memoria se hace bajo la siguiente frmula 20*renglon + columna + direccin_base. En cambio nomb tiene 10 apuntadores a elementos. NOTA: si cada apuntador en nomb indica un arreglo de 20 elementos entonces y solamente entonces 200 chars estarn disponibles (10 elementos). Con el primer tipo de declaracin se tiene la ventaja de que cada apuntador puede apuntar a arreglos de diferente longitud. Considerar: char *nomb[] = { "No mes", "Ene", "Feb", "Mar", .... }; char anomb[][15] = { "No mes", "Ene", "Feb", "Mar", ... }; Lo cual grficamente se muestra en la figura 8.2. Se puede indicar que se hace un manejo ms eficiente del espacio haciendo uso de un arreglo de apuntadores y usando un arreglo bidimensional.

14

Figura de Arreglo de 2 dimensiones VS. arreglo de apuntadores.

Arreglos de apuntadores En C se pueden tener arreglos de apuntadores ya que los apuntadores son variables.A continuacin se muestra un ejemplo de su uso: ordenar las lneas de un texto de diferente longitud.Los arreglos de apuntadores son una representacin de datos que manejan de una forma eficiente y conveniente lneas de texto de longitud variable. Cmo se puede hacer lo anterior? Guardar todas las lneas en un arreglo de tipo char grande. Observando que \n marca el fin de cada lnea. Ver figura siguiente. Guardar los apuntadores en un arreglo diferente donde cada apuntador apunta al primer caracter de cada lnea. Comparar dos lneas usando la funcin de la biblioteca estndar strcmp(). Si dos lneas estn desacomodadas -- intercambiar (swap) los apuntadores (no el texto). \\

15

Figura de arreglo de apuntadores

Apuntadores a funciones Los apuntadores a funciones son quiz uno de los usos ms confusos de los apuntadores en C. Los apuntadores a funciones no son tan comunes como otros usos que tienen los apuntadores. Sin embargo, un uso comn es cuando se pasan apuntadores a funciones como parmetros en la llamada a una funcin. Lo anterior es especialmente til cuando se deben usar distintas funciones quizs para realizar tareas similares con los datos. Por ejemplo, se pueden pasar los datos y la funcin que ser usada por alguna funcin de control. Como se ver ms adelante la biblioteca estndar de C da funciones para ordenamiento (qsort) y para realizar bsqueda (bsearch), a las cuales se les pueden pasar funciones. Para declarar un apuntador a una funcin se debe hacer: int (*pf) (); Lo cual declara un apuntador pf a una funcin que regresa un tipo de dato int. Todava no se ha indicado a que funcin apunta. Suponiendo que se tiene una funcin int f(), entonces simplemente se debe escribir: pf = &f; para que apunte a la funcin . Para que trabaje en forma completa el compilador es conveniente que se tengan los prototipos completos de las funciones y los apuntadores a las funciones, por ejemplo: int f(int); int (*pf) (int) = &f;

16

Ahora f() regresa un entero y toma un entero como parmetro. Se pueden hacer cosas como: ans = f(5); ans = pf(5); los cuales son equivalentes. La funcin de la biblioteca estndar qsort es muy til y esta diseada para ordenar un arreglo usando un valor como llave de cualquier tipo para ordenar en forma ascendente. El prototipo de la funcin qsort de la biblioteca stdlib.h es: void qsort(void *base, size_t nmiemb, size_t tam, int (*compar)(const void *, const void *)); El argumento base apunta al comienzo del vector que ser ordenado, nmiemb indica el tamao del arreglo, tam es el tamao en bytes de cada elemento del arreglo y el argumento final compar es un apuntador a una funcin. La funcin qsort llama a la funcin compar la cual es definida por el usuario para comparar los datos cuando se ordenen. Observar que qsort conserva su independencia respecto al tipo de dato al dejarle la responsabilidad al usuario. La funcin compar debe regresar un determinado valor entero de acuerdo al resultado de comparacin, que debe ser: menor que cero : si el primer valor es menor que el segundo. cero : si el primer valor es igual que el segundo. mayor que cero : si el primer valor es mayor que el segundo. A continuacin se muestra un ejemplo que ordena un arreglo de caracteres, observar que en la funcin comp, se hace un cast para forzar el tipo void * al tipo char *. #include <stdlib.h> int comp(const void *i, const void *j); main() {

17

int i; char cad[] = "facultad de ciencias fisico-matematicas"; printf("\n\nArreglo original: \n"); for (i=0; i<strlen(cad); i++) printf("%c", cad[i]); qsort(cad, strlen(cad), sizeof(char), comp ); printf("\n\nArreglo ordenado: \n"); for (i=0; i<strlen(cad); i++) printf("%c", cad[i]); printf("\n"); } int comp(const void *i, const void *j) { char *a, *b; a = (char *) i; /* Para forzar void * al tipo char *, se hace cast */ b = (char *) j; /* return *a - *b; } empleando (char *) */

18

Bibliografa:
http://eztigma.brinkster.net/apuntadores.html http://es.wikibooks.org/wiki/Programaci%C3%B3n_en_C%2B%2B/Punteros https://www.itescam.edu.mx/principal/sylabus/fpdb/recursos/r43599.PDF http://www.fismat.umich.mx/mn1/manual/node9.html http://linuxupc.upc.es/~pep/OLD/Punteros.html http://maxus.fis.usal.es/FICHAS_C.WEB/07xx_PAGS/0701.html http://www.programatium.com/manuales/c/11.htm

19

Potrebbero piacerti anche