1. Programación en C (III Parte) 05/06/2011 Realizado por Mariela Curiel Universidad Simón Bolívar Junio, 2011
2. Apuntadores Manejo de memoria dinámica. Listas Línea de comandos del main() Entrada/Salida Contenido 05/06/2011 2
3. Funciones Apuntadores Manejo de memoria dinámica. Listas Línea de comandos del Main Entrada/Salida Contenido 05/06/2011 3
4. Los apuntadores en el Lenguaje C, son variables que poseen la dirección de la ubicación en memoria de otras variables. Declaración de un apuntador: tipo de variable apuntada *nombre_apunt; int *pint ; double *pfloat ; char *letra , *codigo , *caracter ; Apuntadores
5. int x; /* se crea en memoriauna variable entera */ int *p; /* se declara un apuntadorquecontendrá la dirección de una variable entera */ p = &x; /* al apuntador se le asigna la dirección de la variable entera (x) */ Apuntadores
6. Apuntadores int c, ...; int *p; c = 63; p = &c; 0 4 8 12 16 c: 63 p: 20 24 28 4
8. Apuntadores int c,…; int *p; c = 63; p = &c; *p = 40; 0 4 8 12 16 c: 40 p: 20 24 28 4
9. IMPORTANTE: Cuando se declara un apuntador no apunta a ningún lugar. Es necesario inicializarlo antes de usarlo. int *p; *p = 100; /* error */ El uso correcto es: int *p, x; p = &x; // se inicializa el apuntador *p = 100; // se está dando un valor a lo apuntado por p. Apuntadores
10.
11. Para hallar el valor apuntado se utiliza el operador (*). Así, son equivalentes:y = x ; y = *p; // tomando en cuenta la asignación de la lámina anterior. printf("%d" , x ) ; printf("%d" , *p) ; Apuntadores
12. Incremento de apuntadores int *dir; .... dir + 1; /* Ok */ dir += 10; /* incrementadirparaapuntar 10 elementos. masadelante */ Operaciones sobre Apuntadores
13.
14. Un apuntador a entero o float sumará 4 bytes a la direcciónApuntadores
15. Comparación de apuntadores Sólo se podrán comparar apuntadores del mismo tipo. int t[10]; int *p; for (p=t; p < t+10;p++) *p = 1; Operaciones sobre Apuntadores
16. Resta de apuntadores: la diferenciaproporciona el número de elementos del tipo en cuestión, situados entre las dos direcciones. intstrlen(char *s){ char *p=s; while (*p != ‘’) p++; return p - s; } Operaciones sobre Apuntadores
17. Asignaciones y el apuntador NULL int *p, *t, a[10]; p = a: t = p; p = NULL; Operaciones sobre Apuntadores
19. Apuntadores y Arreglos El nombre de un arreglo , para el compilador C , es un APUNTADOR inicializado con la dirección del primer elemento del arreglo. float var,conjunto[]={8.0,7.0,6.0,5.0); float *pf; pf = conjunto; /* equivale a hacer pf = &conjunto[0]*/ var1 = *pf; *pf = 25.1;
20. Recuperar un elemento de un arreglo usando apuntadores: int *pa, a[10]; pa = a; /* equivale a pa = &a[0]*/ también .... x = *(pa + i) equivale a x = a[i] Apuntadores y Arreglos
21. Un arreglo como apuntador: a[i] puede escribirse como *(a + i). i.e. &a[i] = a + i. El apuntador lo podemos tratar como arreglo: pa[i] en lugar de *(pa + i). Apuntadores y Arreglos
22.
23. Apuntadores y Arreglos ASIGNACIONES ERRONEAS intconjunto[3], lista[] = {5,6,7}; int *apuntador ; apuntador = lista ; /* correcto */ conjunto = apuntador; /* ERROR */ lista = conjunto ; /* ERROR */ apuntador = &conjunto /* ERROR no se puedeaplicar el operador “&” aunaconstante */
26. Los arreglos de apuntadorespuedeninicializarse de la misma forma que un arreglocomún: char *months = {``no month'', ``jan'', ``feb”, ...}; Arreglos de Apuntadores
27. Los apuntadores pueden servir para el manejo de estructuras, y su alojamiento dinámico. Tienen además la propiedad de poder direccionar a los miembros de las mismas utilizando el operador (->) . Apuntadores a Estructuras
29. Unaestructura, se puedepasar a unafuncióncomoargumento: structconjunto { int a ; double b ; char c[5] ; } datos; //declaración de la variable datos void funcion( structconjunto); //prototipo . . . funcion(datos); // llamada APUNTADORES COMO PARAMETROS DE FUNCIONES
30. Otra forma equivalenteesutilizar un apuntador a la estructura structconjunto { int a ; double b ; char c[5] ; } a; // declaración de la variable “a” void una_funcion( structconjunto*); //prototipo una_funcion(&a); //llamada APUNTADORES COMO PARAMETROS DE FUNCIONES
31. Podemos declarar funciones que devuelven apuntadores a un tipo de datos: char *funcion1(char * var1 ) ; double *funcion2(int i, double j, char *k ) ; struct item *funcion3( struct stock *puntst ) ; APUNTADORES COMO RESULTADO DE UNA FUNCION
32. El retorno de las mismas puede inicializar apuntadores del mismo tipo al que se devuelve o de un tipo distinto. void *malloc(int tamaño) ; p = (double *)malloc( 64 ) ; APUNTADORES COMO RESULTADO DE UNA FUNCION
33. Cuando en el lenguaje C se pasan argumentos a las funciones, el pasaje de parámetros es por valor. Los apuntadores se utilizan para realizar el pasaje de parámetros por referencia. int a,b; swap(a, b) /* NO FUNCIONA */. Apuntadores y Funciones
34.
35. Prototipo void una_funcion( structconjunto *p); ….. structconjunto { int a ; double b ; char c[5] ; } a; una_funcion(&a); Declaración de la variable a Llamada con la dirección de la variable APUNTADORES COMO PARAMETROS DE FUNCIONES
36. Apuntadores y Funciones Cuando un arreglo se pasa a unafunción comoparámetrolo querealmente se estápasandoeslaubicación en memoria de su primer elemento: strlen(s) equivalestrlen(&s[0]) La declaración de la funciónes: intstrlen(char s[]) ; Y unadeclaraciónequivalentees : intstrlen(char *s); porque char s[] es similar a char *s. llamada
37. strlen() esunafunción de la libreríaestándarqueretorna la longitud de un string: intstrlen(char *s) { char *p = s; while (*p != `’); p++; return p-s; } llamada: char nombre[10]; strlen(nombre); Apuntadores y Funciones
40. Cuando se pasa un arreglo de dos dimensiones a unafunción, se pasa el número de columnas, -- el número de filasesirrelevante. Arreglos Multidimensionales y Apuntadores
41. Considere la siguientematriz: int a[5][35] Para pasarlacomoargumento a unafunción, ésta se declaracomo: f(int a[5][35]) {.....} f(int a[][35]) {.....} o incluso: f(int (*a)[35]) {.....} Arreglos Multidimensionales y Apuntadores
42. int (*a)[35]; declara un apuntador a un arreglo de 35 enteros. int *a[35]; declara un arreglo de 35 apuntadores a enteros. Arreglos Multidimensionales y Apuntadores
43.
44. nametiene 10 elementosque son apuntadores no inicilizados.Laventajaesque los vectores de cadafilapueden ser de longitudes diferentes.ArreglosMultidimensionales y Apuntadores
46. La Funcciónmallocse usaparaobtenerunaporcióncontigua de memoria. void *malloc(size_tnumber_of_bytes) Retorna un apuntador del tipovoid *.Si la memoria no se puedeasignarretorna NULL El tipo del argumento(size_t)estadefinido en stdlib.h y es un tipounsigned. Memoria Dinámica
47. char *cp; cp = malloc(100); La instrucción anterior solicita al sistema operativo 100 bytes consecutivos y asigna la dirección de comienzo de este bloque a al apuntador cp. Memoria Dinámica
48. Es común usar la función sizeof() para especificar el número de bytes de un determinado tipo o estructura de datos. int *ip; ip = (int *) malloc(100*sizeof(int)); Memoria Dinámica
49. La función sizeof puede usarse para encontrar el tamaño de cualquier tipo de datos, variable o estructura. int i; struct COORD {float x,y,z}; typedef struct COORD PT; sizeof(int), sizeof(i), sizeof(struct COORD) y sizeof(PT) son todos válidos Memoria Dinámica
50. ip = (int *)malloc(100*sizeof(int)); Aquí haremos uso de la relación entre apuntadores y arreglos y trataremos la memoria reservada como un arreglo. En lugar de *ip = 100, podemos hacer: ip[0] = 100; o for(i=0;i<100;++i) printf("%d",ip[i]);
51. Cuando se termina de usar una porción de memoria se debe liberar usando la función free(). free() toma un apuntador como argumento y libera la memoria direccionada por el apuntador. Memoria Dinámica
52. Queremos almacenar 3 enteros, en una estructura de datos dinámica (lista). Mostraremos cómo se hace de una forma sencilla: 1. Primero crearemos tres variables de un determinado tipo (struct list). Dichas variables contendrán el valor entero a almacenar y un apuntador inicializado en NULL. 2. Luego colocaremos el apuntador de una variable a “apuntar” a la siguiente. Creación de Estructuras de datos dinámicas 05/06/2011
53. Graficamente. Paso 1 struct list{ int data; struct list *next; }; struct list a, b, c; a.data = 1; b.data = 2; c.data = 3; a.next = b.next = c.next = NULL; 1 NULL a b NULL 2 3 c NULL Estructuras autoreferenciadas
54. a b c 1 3 2 NULL a.next = &b; b.next = &c; Paso 2 a.next -> data es 2 a.next -> next -> data es 3 Estructuras autoreferenciadas
55. Ahora, cada elemento de la lista lo crearemos dinámicamente según se necesite. Utilizaremos typedef, para crear tipos de datos que permiten una programación más ellegante. Esta vez, cada elemento de la lista almacenará un carácter y el apuntador al próximo elemento de la lista. Otro Ejemplo 05/06/2011
56. // Definición de tipos. Archivo list.h #define NULL 0 typedef char DATA; struct linked_list{ DATA d; struct linked_list *next; }; typedef struct linked_list ELEMENT; typedef ELEMENT *LINK; Estructurasautoreferenciadas
57. El programa de la siguiente lámina recibe como parámetro un arreglo de caracteres y los coloca en una lista. Las variables head y tail apuntan en todo momento a la cabeza y cola de la lista respectivamente. Al comienzo apuntan a NULL. Estructurasautoreferenciadas 05/06/2011
58. #include “list.h” LINK s_to_l (char s[]) { LINK head = NULL, tail=NULL; int i; if (s[0] != ‘’) { head = (LINK) malloc(sizeof(ELEMENT)); head -> d = s[0]; tail = head; for (i = 1; s[i] != ‘’, ++i) { tail ->next = (LINK) malloc(sizeof(ELEMENT)); tail = tail->next; tail -> d = s[i]; } tail ->next = NULL; return(head); } }
59. A head ? tail Se recibe como parámetro El string “AB” #include “list.h” LINK s_to_l (char s[]) { LINK head = NULL, tail=NULL; int i; if (s[0] != ‘’) { head = (LINK) malloc(sizeof(ELEMENT)); head -> d = s[0]; tail = head; for (i = 1; s[i] != ‘’, ++i) { tail ->next = (LINK) malloc(sizeof(ELEMENT)); tail = tail->next; tail -> d = s[i]; } tail ->next = NULL; return(head); } }
60. head A ? tail head A ? B tail LINK head = NULL, tail=NULL; inti; if (s[0] != ‘’) { head = (LINK) malloc(sizeof(ELEMENT)); head -> d = s[0]; tail = head; for (i = 1; s[i] != ‘’, ++i) { tail ->next = (LINK) malloc(sizeof(ELEMENT)); tail = tail->next; tail -> d = s[i]; } tail ->next = NULL; return(head); } }
61. tail head A NULL B LINK head = NULL, tail=NULL; int i; if (s[0] != ‘’) { head = (LINK) malloc(sizeof(ELEMENT)); head -> d = s[0]; tail = head; for (i = 1; s[i] != ‘’, ++i) { tail ->next = (LINK) malloc(sizeof(ELEMENT)); tail = tail->next; tail -> d = s[i]; } tail ->next = NULL; return(head); } }
62.
63. argv es un arreglo de strings. Cada posición del arreglo contiene un argumento. Argumentos del Main
64. Línea de Comandos #include<stdio.h> main (int argc, char **argv) { /* programa que imprime los argumentos de la línea de comandos */ int i; printf(``argc = %d'',argc); for (i=0;i<argc;++i) printf(``argv[%d]:%s'',i,argv[i]); }
65. Si se invoca el programa (argum) con los siguientesargumentos: argum f1 “f2” f3 4 stop! La salidaserá: argc = 6 argv[0] = argum argv[1] = f1 argv[2] = f2 argv[3] = f3 argv[4] = 4 argv[5] = stop! Los caracteres “” se ignoran. Línea de Comandos
66. Brian Kernighan y Dennis Ritchie. El Lenguaje de Programación C. Prentice Hall. http://www.its.strath.ac.uk/cources/c Bibliografía 05/06/2011 58