You are on page 1of 61

Apuntadores

Declaraciones e inicializacin de variables apuntadores


Los apuntadores son variables que contienen direcciones de memoria como sus valores. Un apuntador contiene la direccin de una variable que contiene un valor especfico.
Un nombre de variable se refiere directamente a un valor y un apuntador se refiere indirectamente a un valor. Referirse a un valor a travs de un apuntador se conoce como indireccin.

Declaraciones e inicializacin de variables apuntadores


Los apuntadores, como cualquier otra variable, deben ser declarados antes de que puedan ser utilizador. Ejem:

int *apuntadorCont, cont;


Declara la variable apuntadorCon de tipo int * (es decir, un apuntado a un valor entero), y se lee apuntadorCont es un apuntador a int, o bien apuntadorCont apunta a un objeto de tipo entero.

Y la variable cont se declara como entero.

Declaraciones e inicializacin de variables apuntadores


El * se utiliza de esta forma en la

declaracin, para indicar que la variable que se est declarando es un apuntador.


Los apuntadores pueden ser declarados

para apuntar objetos de cualquier tipo de datos.

Declaraciones e inicializacin de variables apuntadores


Los apuntadores deben ser inicializados

cuando son declarados o en un enunciado de asignacin.


Un apuntador puede ser inicializado a 0,

NULL, o a una direccin. Un apuntador con valor NULL apunta a nada. NULL es una constante simblica definida en stdio.h

Declaraciones e inicializacin de variables apuntadores


Inicializar un apuntador a 0 es equivalente

que inicializarlo a NULL, pero NULL es preferible.


Cuando se asigna 0, primero se convierte a

un apuntador del tipo apropiado.

Operadores de apuntador
El &, u operador de direccin, es un operador unario que regresa la direccin de su operando. Ejem:

int y = 5; int *apuntador_y: apuntador_y = &y; // asigna la direccin de la //variable y a la variable de //apuntador apuntador_y La variable apuntador_y apunta a y

Operadores de apuntador
El operando del operador de direccin ( &

) debe ser una variable; no puede aplicarse a constantes, expresiones, o variables declaradas con la clase de almacenamiento register.

Operadores de apuntador
El operador *, conocido comnmente

como el operador de indireccin o de desreferencia, regresa el valor del objeto hacia el cual su operando apunta (es decir, un apuntador). Ejem:

printf(%d, *apuntador_y); //imprime el //valor de la variable y, es decir 5

Operadores de apuntador
Los operadores & y * son complementarios, cuando se aplican consecutivamente a una variable apuntador, en cualquier orden, el resultado ser el mismo.
Son de tipo unario, se asocia de izquierda a derecha. Fig 7.4

Operadores de apuntador

Cmo llamar funciones por referencia


Muchas funciones requieren la capacidad de modificar una o ms variables del llamador, o de pasar un apuntador a un objeto de datos grande, para evitar la sobrecarga de par el objeto en llamada por valor.
En C, los programadores utilizan apuntadores y el operador de indireccin para simular llamadas por referencia.

Cmo llamar funciones por referencia


Esto se hace aplicando el operador de direccin (&), a la variables cuyo valor deber ser modificado.
Cuando se pasa a una funcin la direccin de la variable, el operador de indireccin (*), puede ser utilizado en la funcin para modificar el valor de

esa posicin en la memoria del llamador. (fig 7.6, 7.7)

Expresiones y aritmtica de apuntadores


Los apuntadores son operandos vlidos en

expresiones aritmticas, en expresiones de asignacin y en expresiones de comparacin.

Expresiones y aritmtica de apuntadores


Con operadores se pueden ejecutar un

conjunto limitado de operaciones aritmticas:


Un operador puede ser incrementado (++). O decrementado (--) Se puede aadir un entero a apuntador (+ o +=) Se puede restar un entero a apuntador (- o -=)

Expresiones y aritmtica de apuntadores


Cuando se aade o se resta un entero a un apuntador, el apuntador no se incrementa o decrementa slo por el valor de dicho entero, sino por el entero, multiplicado por el tamao del objeto al cual el apuntador se refiere.
El nm de bytes depende del tipo de datos del

objeto. Al ejecutar la aritmtica de apuntadores en un arreglo de caracteres, los resultados sern consistentes con la aritmtica normal, porque cada carcter tiene una longitud de un byte.

Expresiones y aritmtica de apuntadores


Si una apuntador est siendo incrementado o decrementado en 1, pueden utilizarse los operadores de incremento (++) o decremento (--), los enunciados:
++vPtr; vPtr++;

Incrementan el apuntador, para que apunte a la siguiente posicin dentro del arreglo.

Expresiones y aritmtica de apuntadores


Los enunciados:
--vPtr; vPtr--;

decrementan el apuntador, para que apunte al elemento anterior del arreglo.

Expresiones y aritmtica de apuntadores


Las variables de apuntador pueden ser restadas una de otra. Ejem: si vPtr contiene la posicin 3000 y v2Ptr contienen la direccin 3008, el enunciado:
x = v2Ptr - vPtr;

Asignara a x el nm. De elementos del arreglo vPtr hasta v2Ptr, es decir, 2.

Expresiones y aritmtica de apuntadores


La aritmtica de apuntadores no tiene

significado, a menos de que se ejecute en un arreglo (no podemos suponer que 2 variables del mismo tipo se almacenen de manera contigua en memoria, a menos que sean elementos adyacente de un arreglo).

Expresiones y aritmtica de apuntadores


Un apuntador puede ser asignado a otro

apuntador, si ambos son del mismo tipo.


De lo contrario deber usarse un operador

cast para convertir el apuntador a la derecha de la asignacin del tipo de apuntador de la izquierda de la asignacin.

Expresiones y aritmtica de apuntadores


La excepcin a la regla es el apuntador void (void *) que es un apuntador genrico, que puede representar cualquier tipo de apuntador:
Todos los tipos de apuntador pueden ser asignados a un apuntador void. Un apuntador void puede ser asignado a un apuntador de cualquier tipo.

Un apuntador void no puede ser desferenciado.

Expresiones y aritmtica de apuntadores


Los apuntadores pueden ser comparados mediante operadores de igualdad y relacionales, pero dichas comparaciones no tendrn sentido a menos que los apuntadores seales a miembros del mismo arreglo.
Las comparaciones de apuntadores comparar las direcciones almacenadas en los mismos. Es comn determinar si un apuntador es NULL.

Relaciones entre apuntadores y arreglos


Estn relacionados en C en forma ntima y pueden ser utilizados casi en forma indistinta. Un nombre de arreglo puede ser considerado como un apuntador constante.
Los apuntadores pueder utilizarse para hacer cualquier operacin que involucre subndices de arreglos.

Relaciones entre apuntadores y arreglos


Ejemplo: int b[5], *apuntB; apuntB = b; //equivalente a apuntB = &b[0];

//La notacin apuntador/desplazamiento *(apuntB + 3)//hace refencia al elemento b[3] //Los parntesis son necesarios *apuntB + 3; //suma 3 al contenido de b[0]

Relaciones entre apuntadores y arreglos


&b[3] //puede ser escrita con la expresin //apuntador apuntB + 3 //El mismo arreglo puede tratarse como apuntador *(b + 3) //hace refencia al elemento b[3] // b apunta al primer elemento del arreglo
En general todas las expresiones de arreglos con subndice pueden ser escritas mediante un apuntador y un desplazamiento.

Relaciones entre apuntadores y arreglos


Los apuntadores pueden tener subndices

de la misma forma que los arreglos, mediante la notacin apuntador/subndice: apuntB[1] //se refiere al elemento b[1]

Relaciones entre apuntadores y arreglos


El nombre de un arreglo es un apuntador constante; siempre apunta al principio del arreglo. Por lo que:

b += 3; //error de sintaxis
Resulta invlida, porque intenta modificar el valor del nombre de un arreglo con aritmtica de apuntador (fig. 7.20, 7.21).

Arreglos de apuntadores
Los arreglos pueden contener apuntadores.
Un uso comn es formar un arreglo de cadenas.

Cada entrada en el arreglo es una cadena.


En C una cadena es en esencia un apuntador a su primer carcter. Por lo que en un arreglo de cadenas cada entrada es de hecho un apuntador al primer carcter de una cadena.

Arreglos de apuntadores
Ejemplo:

char *noms[4] = {hil, luis,carlo, beto};


noms[4] indica un arreglo de cuatro elementos. char * indica que cada elemento del arreglo noms es del tipo apuntador char. Cada una de las cadenas est almacenada en memoria como una cadena de caracteres terminadas por NULL. En el arreglo slo estn los apuntadores (figura).

Arreglos dinmicos.
Los punteros indican direcciones de memoria.
Para usarlos hay que saber qu tipo de dato hay en

esa direccin, porque slo "sabemos" trabajar con datos.


Existe un puntero comodn, que no tiene un tipo de dato asociado:

void *

Conversin de datos en punteros


Se puede recuperar un puntero a dato a partir del comodn con un cast: (tipo *) <comodn> Ejem.

void *ap; int x, *apx; apx=NULL; apx=(int *)ap;

Conversin de datos en punteros


Adems existe la constante NULL que

indica que un puntero no apunta a ninguna direccin.

Tamao de tipos: sizeof

La memoria que ocupa un dato

depende
del tipo de dato del compilador de la arquitectura

Tamao de tipos: sizeof


El tamao de un dato sencillo de un tipo

dado se calcula con el operador: sizeof( <tipo de dato> )


... tambin se puede usar un dato concreto

de ese tipo sizeof( <dato de tipo> )

Tamao de tipos: sizeof


Ejem.
int i=4; //sizeof regresa como un entero el //num. De bytes del tipo de dato printf("El tamao de un double es %d\n", sizeof(double)); printf("El tamao del entero i es %d\n", sizeof(i));

Tamao de tipos: vectores


El tamao de un vector de tamao fijo es, segn sizeof, igual al espacio que ocupan todos sus elementos. Ejem:
int v[5]; char s[]="Hola mundo"; printf("El vector v tiene %d elementos\n", sizeof(v)); printf("La cadena s tiene %d caracteres\n, sizeof(s));

(fig. 7.16, 7.17)

Tamao de tipos: vectores


Pero si declaramos la cadena como un

puntero, nos da el tamao de un puntero a carcter. Ej. :


char *s="Hola mundo"; printf("El puntero a caracteres s cuesta %d bytes\n", sizeof(*s) );

Reserva de memoria dinmica


Para los datos sencillos (de uno en uno) o

los vectores de tamao fijo el compilador "sabe" cunta memoria utilizar.


Si queremos asignar memoria nosotros

durante la ejecucin debemos saber cunta memoria pedir.

Reserva de memoria dinmica


La memoria se mide en unidades de un

byte. Ej. la memoria necesaria para guardar 100 floats es: 100 * sizeof( float )

Reserva de memoria: malloc


Podemos pedir memoria al SO con

void* malloc( size_t )


donde

size_t = unsigned int

Reserva de memoria: inicializacin


La posicin retornada se refiere al

inicio del bloque de memoria que nos da el SO para trabajar.


Cuando no hay bastante memoria, se

retorna el puntero NULL.

Reserva de memoria: malloc


La memoria reservada por malloc no tiene

ningn valor definido: hay que inicializarla.


Para guardar algo en esa memoria hay que

obtener un puntero a los datos que queremos poner en ella usamos un "cast de void al tipo requerido.

Reserva de memoria: inicializacin


Ejem.
int n, i; int *x; printf("Cuntos enteros? "); scanf("%d", &n); x=(int *) malloc( n*sizeof(int) ); if( x==NULL ) { printf("Error: no hay bastante memoria\n ); exit(-1); } for(i=0; i<n; i++) x[i]=0;

Reserva de memoria: calloc


Una alternativa a malloc es calloc void* calloc( size_t, size_t )

calloc reserva espacio para tantos elementos como indica el primer argumento, cada uno del tamao que indica el segundo.
calloc inicializa todos los bytes de la memoria a cero. Si accedemos a la memoria como a un vector de enteros,todos valen cero al principio.

Reserva de memoria: calloc


Son equivalentes:

calloc( n_elementos, sizeof(elemento) ) y malloc( n_elementos * sizeof(elemento )


seguido de un bucle en el que se hacen

todos los elementos del array cero.

Reserva de memoria: calloc


Ejem:

int *x, n; x=(int*)calloc(n, sizeof(int) ); los x[0], x[1], ..., x[n-1] valen cero

Liberacin de memoria: free


La memoria del ordenador es finita ... adems, cuanta ms memoria libre tiene ms rpido funciona. Cuando no vamos a usar ms en nuestro programa un bloque de memoria lo liberamos con: void free( void* ) a la que le pasamos un puntero que apunta a la misma direccin que el que nos retorn malloc o calloc .

Liberacin de memoria: free


Ejem.

float *x, *y; int n; x=(float*)calloc( n, sizeof(float) ); y=(float*)calloc( n, sizeof(float) ); free( y ); free( x );

Ordenamiento por Insercin


ORDENAMIENTO POR INSERCIN SIMPLE
Reordena un conjunto de elementos en un arreglo ordenado existente. Por lo regular es mejor que el ordenamiento por burbuja (mientras ms prximo est el archivo a ser ordenado, ser ms eficiente). Se usa slo una variable temporal (y)

Ordenamiento por Insercin

Shell Sort
Shell sort u ordenamiento por disminucin de incremento. Llamado as en honor a su creador (Donald Shell,1959).
Ordena suarreglos separados del arreglo original. Los cuales contienen todo elemento k-simo del arreglo original. El valor de k se llama incremento.

Shell Sort
Se ordena los primeros k subarreglos

(en general por insercin simple), se elige un nuevo valor menor de k y se vuelve a particionar el arreglo en un nuevo conjunto de subarreglos.

Shell Sort
Cada uno de esos subarreglos ms

grandes se ordena y se repite el proceso una vez ms con un valor an ms pequeo de k.


Al final, el valor de k se hace 1, de tal

manera que se ordena el subarreglo completo.

Shell Sort
Secuencia (5, 3, 1)

Shell Sort

incrmnts:arreglo que contiene a los incrementos

decrecientes.
numinc: nm. De elementos de incrmnts

Shell Sort

Apuntadores a funciones.
Un apuntador a una funcin contiene la

direccin de la funcin en memoria.


El nombre de la funcin es realmente la

direccin inicial en memoria del cdigo que ejecuta la tarea de dicha funcin.

Apuntadores a funciones.
Los apuntadores a las funciones pueden ser

pasados a las funciones, regresado de las funciones, almacenados en arreglos, y asignados a otros apuntadores de funcin.
(fig. 7.26)

Apuntadores a funciones.
Un uso comn de los apuntadores de funcin ocurren en los denominados sistemas manejados por men. Cada opcin est servida por una funcin diferente.
En un arreglo de apuntador a funciones se almacenan apuntadores a cada funcin. La

seleccin del usuario se utiliza en el arreglo como un subndice, y el apuntador en el arreglo se utiliza para llamar a la funcin. (fig. 7.28)

You might also like