apuntadores y estructuras

18

Click here to load reader

Upload: graciela-gomez

Post on 27-Oct-2014

49 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Apuntadores y Estructuras

"Apuntadores y Estructuras" Programac ión C Alberto Pacheco

[email protected] (29/May/2007 11:58am)

Presentación hecha en ExpoVision, Alberto Pacheco, Ver 1.0.55, MEXICO D.R. © 2012

Abstract:

Revisión del tópico más temido y obscuro de Lenguaje C.. los APUNTADORES. Incluye ejemplos y ejercicios.

Keywords:

Lenguaje C, apuntadores, indirección, arreglos, estructuras, memoria dinámica

Contenido

Mapa Conceptual

A b s t r a c t

1. Características de los Apuntadores

4. Apuntadores: Ventajas y Desventajas

5. Apuntadores: Operaciones Básicas

7. Los Datos en Memoria: sizeof()

8. Aritmética de Apuntadores

9. Apuntadores y Cadenas

10. Estructuras

12. Apuntadores y Arreglos de Estructuras

13. Estructuras: Pseudotipos y Parámetros por Refere

14. Asignación Dinámica de Memoria

15. Apuntadores y Arreglos

17. Apuntadores a Funciones

18. Ejercicios

Apuntador: A continuación se resumen sus principales cualidades

Page 2: Apuntadores y Estructuras

Variable que almacena una dirección de memoria.

Una variable de este tipo "apunta" o hace referencia a uno ó más objetos

Desde su declaración "sabe" el tipo de objetos a que hace referencia.

Tipos de apuntadores: a tipos primitivos, arreglos, apuntadores, estructuras y funciones, (*p).field == p->field

El identificador de un arreglo equivale a un apuntador a la dirección del primer elemento, a+i == &a[i] y *(a+i) == a[i]

Parámetros por referencia: en vez de una copia del valor de un parámetro, con apuntadores pasas la dirección del objeto y por lo tanto, la función puede alterar el objeto "externo".

Apuntador Universal: (void*) declara un apuntador genérico, apunta a cualquier tipo de objeto.

Operadores permitidos: asignar, sumar con contantes, restar, comparar, convertir y manejo de bits.

Operadores PROHIBIDOS: multiplicar, dividir y sumar dos o más apuntadores.

Apuntador NULO: valor reservado, dirección cero, significa "apuntador vacío", definido en <stdlib.h>, NULL == (void *)0

PELIGRO: Un apuntador puede accesar indirectamente el contenido de un objeto.

PRECAUCION: Todo apuntador debe inicializarse antes de usarse.

Beneficios:

Page 3: Apuntadores y Estructuras

Generar elementos bajo demanda, asignación dinámica de memoria

Manipular y recorrer grandes espacios de memoria

Generar estructuras de datos complejas

Parámetros de entrada/salida para funciones, parámetros por referencia

Dificultades:

Programación avanzada, caótica y/o complicada

Programación más susceptible de errores muy difíciles de depurar

Dificultad para leer y comprender código

EJERCICIOS

#define NULO ((void *)0)void main(){ int i=5, j; // Datos int *p=NULO, *q=NULO; // Apuntadores printf("\ni=%d, p=%p, q=%p", i, p, q); p = q = &i; // Apuntar al dato *p = 7; // afectar dato (indirección) printf("\ni=%d, p=%p, q=%p", i, p, q); if ( p == q )// Son iguales?

Page 4: Apuntadores y Estructuras

printf("\np es igual a q"); ++*p // incrementa dato, lee dato printf("\ni=%d",i);// i=8 j = *q++;// lee dato, incrementa dirección printf("\nj=%d, p=%p, q=%p", j, p, q); // j=? if ( p != q ) // Diferentes? printf("\np es diferente a q"); if ( q > p ) // Cuál es mayor? printf("\nq es mayor que p");}

Op Función Ejemplo Explicación

(void *)Convierte entero a dirección

(void *)0 dirección nula

*Para declarar apuntadores

int *p;p es un

apuntador

&Obtener

dirección de..q=&i; q apunta a i

=Asignar

direcciónp=q=&i;

p y q apuntan a i

*Operador

indirección*p=7;

a donde apunta p almacena un 7

++Incremento-

dato++*p;

incrementa el valor que apunta p

++ Incremento- *p++; incrementa

Page 5: Apuntadores y Estructuras

apuntador apuntador p

%pEspecificador

tipo apuntadorprintf("%p",p);

imprime dirección

almacenada en p

==igualdad entre apuntadores

p==qregresa falso si no son iguales

!=desigualdad

entre apuntadores

p!=qregresa falso si

son iguales

<menor, <=

menor o igualp<=q

regresa falso si p es mayor que

q

>mayor, >=

mayor o igualp>=q

regresa falso si p es menor que

q

sizeofEspacio que

ocupa un dato en bytes

sizeof(void *)tamaño de cualquier apuntador

Page 6: Apuntadores y Estructuras

#define TYPES 8void main(){ char *tipo[TYPES] = { "char", "short", "int", "long", "float", "double", "long double", "void *" }; int i, tam[TYPES] = { sizeof(char), sizeof(short), sizeof(int), sizeof(long), sizeof(float), sizeof(double), sizeof(long double), sizeof(void *) }; printf("| Tipo-Dato | Bytes |\n"); printf("|-------------|-------|\n"); for (i=0; i<TYPES; i++) printf("| %11s | %2d b. |\n", tipo[i], tam[i]);

Page 7: Apuntadores y Estructuras

printf("|-------------|-------|\n");}

/////////////

main(){ char x[] = "01234567"; char *p = NULL; short *q = (short *)x; int *r = (int *)x; int SIZE = 0; printf("\n\"%s\"={",x); for ( p=x; *p; ++p ) printf("0x%x,",*p); SIZE = p - x + 1; printf("0}\nSize = %d bytes\n",SIZE); for ( p=x; (char *)r-x+sizeof(int)<SIZE; ++p, ++q, ++r ) { printf("\n char[%p]=%x",p,*p); printf("\nshort[%p]=%x",q,*q); printf("\n int[%p]=%x",r,*r);

Page 8: Apuntadores y Estructuras

printf("\n---------------------------\n"); } getchar();}

Notas:

"01234567"={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0}Size = 9 byteschar[0022FF60]=30short[0022FF60]=3130int[0022FF60]=33323130---------------------------char[0022FF61]=31short[0022FF62]=3332int[0022FF64]=37363534---------------------------

int sc( char *s, char *t ){ if ( !s || !t ) return 0; for ( ; *s && *t; s++, t++ ) if ( *s != *t ) break; return *s == *t;}void asg( char *d, char *f ){ while ( *d++ = *f++ );}void idem( char *a, char *b )

Page 9: Apuntadores y Estructuras

{ printf("\n%s! '%s'-'%s'\n",(sc(a,b)?"Iguales":"Diferentes"),a,b);}

Page 10: Apuntadores y Estructuras

main(){ char p[20]="Hola", q[20]="Adios"; idem(p,q); asg(p,q); idem(p,q); getchar();}

Estructura: Permite definir un tipo-derivado que asemeja un "registro" compuesto por campos/miembros heterogeneos. Para acceder cada miembro de una variable tipo estructura se usa el operador-punto. Puede usarse una lista de inicialización para inicializar una estructura.

struct tipo {char member_1;int member_2;};struct tipo x, y={'U',2};x.member_1 = 'A';

Pseudotipos (typedef): Es un alias para declarar variables de tipo struct.

Apuntadores a estructuras: Se usa la notación p->member

Arreglos de estructuras:

struct tipo x[8];

Page 11: Apuntadores y Estructuras

typedef struct {char member_1;int member_2;} s_type;s_type x={'U',2}, *p = &x;p->member_1 = 'R'; // Equivale a (*p).member_1 = 'R';

struct Alumno { char *nombre; unsigned calif;};void main(){ struct Alumno *p, grupo[] = { {"Juan", 73}, {"Ana", 86}, {"Luis", 80}, {(void *)0, 0} }; printf("|--------------|\n"); for (p=grupo; p->nombre; p++) printf("| %6s | %3d |\n", p->nombre, p->calif); printf("|--------------|\n");}

typedef struct { char *nombre; unsigned calif;} Alumno;unsigned mayor_calif(Alumno *p){ unsigned mayor = 0; for (; p->nombre; p++) if ( p->calif > mayor ) mayor = p->calif; return mayor;}void main()

Page 12: Apuntadores y Estructuras

{ Alumno *p, grupo[] = { {"Juan", 73}, {"Ana", 86}, {"Luis", 80}, {NULL, 0} }; printf("|--------------|\n"); for ( p=grupo; p->nombre; p++ ) printf("| %6s | %3d |\n", p->nombre, p->calif); printf("|--------------|\n"); printf("\nla calificación más alta del grupo es: %d", mayor_calif(grupo));}

//////////

#include <stdlib.h> // malloc#include <assert.h> // assertvoid main(){ const int TAM = 10; int i, *p, *q; p = (int *)malloc(TAM*sizeof(int)); assert(p); // Termina si falla asignación de memoria (p==NULL)

for (i=0, q=p; i<TAM; i++, q++ ) { *q = i; printf("\nq=%p, dato=%d", q, *q);

Page 13: Apuntadores y Estructuras

} free(p);}

Ejemplo ilustrativo sobre similitudes y diferencias entre las siguientes declaraciones:

Arreglo 3 reng x 4 col.

Arreglo de apuntadores a

enteros

Apuntador a un arreglo de enteros

Apuntador a apuntadores a

enteros int t[3]

[4];  int *p[3];  int (*q)[4];  int **r;

   1 2 3 4    1 2 3 4

   1 2 3 4    1 2 3 4

   1 2 3 4      ...      ...

   1 2 3 4

Tabla 3 x 4 Tabla 3 x n Tabla n x 4 Tabla m x n

#include <stdio.h>#define P(s) printf("\n%10s=%d", #s, (s))#define L() printf("\n----------------\n")main(){ int a[6] = { 9,8,7,6,5,4 }; int *p[6] = { a+5, a+4, a+3, a+2, a+1, a }; int (*q)[6] = &a; int **r = p; P(*p[0]); P(**p); L(); P(*p[1]); P(**(p+1)); L();

Page 14: Apuntadores y Estructuras

P((*q)[0]); P(**q); L(); P((*q)[1]); P(*(*q+1)); L(); P(*r[0]); P(**r); L(); P(*r[1]); P(**(r+1)); L();}

///&&&&&&&&

#include <stdio.h>void f1() { printf("\nCorriendo f1()"); }void f2() { printf("\nCorriendo f2()"); }void f3() { printf("\nCorriendo f3()"); }typedef void (*ApFun)(); // KISS main() { void (*p)() = f1; (*p)(); ApFun q = f2; (*f2)(); ApFun a[] = { f1, f2 ,f3, NULL }; int i; for ( i=0; a[i]; i++ ) (*a[i])();}

Page 15: Apuntadores y Estructuras

Indicaciones Generales: Reusando el pseudotipo Alumno defina las siguientes funciones y ejecútelas desde main con datos de ejemplo de 5-10 alumnos.

Problema [+3pts]: Busca en un arreglo p un alumno y regresa su calificación o -1 si no lo encuentra

   Prototipo: int busca_alumno(Alumno *p, char *alumno)

   Testing: Llamar e imprimir el resultado de dos búsquedas, una exitosa y otra que falle. Problema [+3pts]: Comparar dos arreglos (p,q) y que regrese verdadero si ambos arreglos son idénticos

   Prototipo: int compara_alumnos(Alumno *p, Alumno *q)

   Testing: Llamar e imprimir el resultado de dos búsquedas, una exitosa y otra que falle. Problema [+4pts]: Copiar de un arreglo (p) todos sólo el conjunto de alumnos cuya calificación sea mayor o igual a calif

   Prototipo: Alumno *copiar_aprobados(Alumno *p, unsigned calif)

   Testing: Llamar e imprimir el resultado de dos copias, una con calif de 60 y otra con 70.

[C Pointers]

Wikibooks, "Programming:Pointers and Arrays", 2005.http://en.wikibooks.org/wiki/C_Programming/Pointers_and_arrays