.: Men� :.

Made in Ecuador
:: Home :.
:: Programaci�n :.
 Introducci�n
 Soluci�n de un problema
 Objetivos de la Programaci�n
 Herramientas para Programar
 Programaci�n Estructurda
 Otras T�cnicas
:: Principiante :.
 �Que es Turbo Pascal?
 Estructura de un programa
 Declaraci�n de Variables
 Definici�n de Tipos
 Operadores
 Expresiones
 Instrucciones
 Procedimientos Entrada/Salida
 Mi primer Programa
 Ejercicios Propuestos
:: Medio :.
:: Estructuras de Control :.
   :: Selecci�n :.
 If...Then...Else
 Case...of...Else
   :: Bucles :.
 While...Do
 Repeat...Until
 For...to...Do
:: Tipos Estructurados :.
 Cadenas
 Vectores
 Matrices
 Registros
 Ejercicios Propuestos
:: Avanzado :.
 Archivos
 Punteros
 Modo Grafico
 Modo Print
 Ejercicios Propuestos
:: Experto :.
 Librerias
 Compiladores
 Manejo de Puertos LPT
 Base de Datos en Codigo
 Ejercicios Propuestos
:: Varios :.
 Codigo Fuente
 Resultado Ejercicios Propuestos
 Autor Pagina Web

Enviame un e-mail


Punteros

Lo primero: hay que entender muy bien lo que es un puntero, porque al principio puede se run poco complicado. Un puntero es un tipo de datos (como un INTEGER, por ejemplo) que lo que almacena no es ni un n�mero ni una letra sino una direci�n de memoria. Una posici�n de memoria es una "cosa" del tipo 0xxxxh:0xxxxh que identifica una posici�n de la memoria CONVENCIONAL del ordenador. (Recordemos que el TP 7 s�lo sabe hacer programas para 286, o sea: para modo real, por lo tanto s�lo podemos usar la memoria convencional [esto en realidad es falso, se puede usar memoria XMS y EMS desde Pascal, pero eso ya es otro tema]) Se dice que un puntero APUNTA a la direci�n de memoria. Para declararlo tenemos el tipo POINTER, con lo que lo declaramos igual que cualquier otro tipo de datos: Var Puntero : Pointer; �Y esto para qu� nos sirve? Pues as�, con lo que sabemos ahora, de nada. Pero lo curioso de los punteros es que podemos decirle qu� es lo que hay en la posici�n de memoria a la que est� apuntando. Me explico: el puntero "se�ala" a un lugar de la memoria de nuestro PC. Pues ese lugar podemos tratarlo como un BYTE, o como un WORD, como un STRING, como una estructura de datos o incluso como otro puntero! En este caso la declaraci�n cambia. En este caso se declara igual que si declar�semos una variable de un tipo concreto s�lo que precedemos el nombre del tipo por el s�mbolo ^. (ALT+94) As� para declarar un puntero de manera que la memoria a la que apunta sea tratada como un byte har�amos esto: Var Puntero : ^Byte; Y lo mismo para una estructura: Type Tipo = record Nombre : String; DNI : Longint; NIF : Char; Calle : String; Edad : Word; End; Var Puntero : ^Tipo; Este tipo de punteros se denominan de una manera especial, son punteros A el tipo de datos. Es decir, este �ltimo ejemplo ser�a un puntero A una estructura (o a la estructura Tipo), el anterior ser�a un puntero a un byte, etc... Y tambi�n pueden hacerse punteros a punteros, punteros a arrays de punteros, etc... pero eso es m�s complicado y vendr� m�s adelante. Pero... �a d�nde apunta un puntero? Eeeeiiinngg? ;) Me refiero: un puntero, nada m�s empezar el programa �apunta a alguna parte? �a d�nde apunta? Pues lo m�s normal es que apunte a la direci�n 0000:0000, ya que las variables suelen inicializarse a cero. Por lo tanto antes de usar el puntero tenemos que hacer que apunte al sitio que nosotros queremos. �Qu� pasa si no lo hacemos? Pues si modificamos un puntero que apunta a 0000:0000... en esa zona de la memoria est� la tabla de los vectores de interrupci�n, si lo modificamos nos cepillaremos esa tabla, con lo cual, en cuanto se genere una interrupci�n del temporizador (una cada 55 milisegundos) nuestro programa nos brindar� un precioso cuelgue. Este tipo de punteros puede ser m�s �til, porque... Ya que un puntero puede apuntar a cualquier parte de la memoria convencional... podemos modificar cualquier posici�n de memoria, tanto si pertenece a nuestro programa como si no. Por ejemplo, el WORD de la posici�n 040h:02h contiene la direci�n del puerto base para el COM2, para leerla s�lo tenemos que hacer que un puntero a un word apunte a esa direci�n (040h:02h) y despu�s leer lo que hay all�. Para hacer que un puntero apunte a un sitio determinado tenemos la funci�n Ptr. La funci�n Ptr acepta como par�metros el segmento y el offset de la direci�n de memoria y nos devuelve como resultado un puntero a esa direci�n. As�, es programa que lee la direci�n del COM2 quedar�a as�: Var Puntero_a_COM2 : ^Word; Begin Puntero_a_COM2 := Ptr($40,2); WriteLn('La direci�n del COM2 es ',Puntero_a_COM2^); End. Una cosa importante a tener en cuenta es que no es lo mismo la direci�n de memoria que lo que hay en esa direci�n. El puntero s�lo contiene la direci�n, no contiene lo que hay en ella. Es decir: el puntero s�lo se�ala al WORD donde est� la direci�n del COM2. El puntero NO almacena la posici�n del COM2. Por eso estas dos lieas son bien diferentes: Puntero := 8; Puntero^ := 8; La primera intenta asignar el valor 8 como direci�n de memoria a la cual tiene que apuntar el puntero. Mientras que la segunda lo que hace es asignar el valor 8 a la direci�n de memoria a la que apunta el puntero. Es muy importante que esto quede claro. Podr�amos decir que Puntero^ es el elemento y Puntero es la direci�n del elemento. Pero la utilidad de los punteros no acaba aqu� ni mucho menos. Creo que ya antes hab�a dicho que las variables de un programa s�lo pod�an ocupar 64 Kbs como mucho. Y... �qu� ha pasado con en resto de los 640 Kbs de memoria? Pues esa memoria se puede usar mediante punteros. Para pedir memoria tenemos la funci�n Getmem y para liberarla una vez ya no la necesitamos tenemos Freemem. A ambas hay que pasarles un puntero y el tama�o de memoria que queremos reservar. Por ejemplo: Getmem(Puntero, 30000); Esto lo que har�a ser�a reservar 30000 bytes de memoria y hacer que el puntero apunte al inicio de esos 30000 bytes. �A qu� tipo de datos tiene que apuntar este puntero? A cualquiera. Si hemos declarado Puntero como un puntero a un byte podremos usar "Puntero^ := valor;" para modificar el primer byte del bloque de memoria que hemos pedido. �Y qu� pasa con el resto? Pues muy sencillo. Podemos "mover" el puntero para que apunte al segundo byte del bloque, o al tercero... Para eso tenemos las funciones INC y DEC. Con INC(PUNTERO); hacemos apuntar el puntero a el siguiente elemento. PERO OJO!!! El siguiente elemento no siempre ser� el siguiente byte. Si hemos definido el puntero como un puntero a words cada vez que usemos INC avanzaremos 2 bytes (que es lo que ocupa un WORD). Y DEC se usa igual y tiene la funci�n inversa. La pega que tiene este m�todo es que nadie nos impide hacer 600.000 INCs y poner el puntero apuntando a una parte de la memoria que no hemos reservado. Y es que para bloques de memoria hay maneras m�s pr�cticas de manejarlos. Para esto son muy �tiles los punteros a arrays. Podemos definir un as�: Type P = Array [0..29999] of Byte; Var Puntero : ^P; Begin Getmem(Puntero, 30000); End. De esta manera definimos un array que empieza en la direci�n a la que apunta el puntero. Esta direci�n, despu�s del Getmem, ser� la direci�n del bloque de memoria. Y a partir de esa direci�n tenemos 29999 elementos m�s en el array. Cada elemento es un Byte, por lo tanto, a cada posici�n del array le corresponde un byte del bloque de memoria que hemos reservado. Ahora, para leer/escribir en ese bloque s�lo tenemos que hacer cosas como esta: Puntero^[8] := Puntero^[15003] - 80; F�cil �no? Pero... �qu� pasa si queremos poner todo el bloque a cero? Podr�amos hacer un bucle FOR que fuese poniendo las posiciones a cero una por una, pero hay una manera mejor. Tenemos la instruci�n FillChar. Esta instruci�n llena con un valor dado el n�mero de posiciones que le digamos a partir de la posici�n que le demos. Se usar�a as�: FillChar(Puntero^, 30000, 0); Atenci�n a que ponemos "Puntero^" y no "Puntero". �Por qu�? Pues porque lo que queremos llenar de ceros no es el puntero sino la memoria a la que apunta ese puntero. (Ya vereis que cuelgues m�s majos os salen cuando se os olvide esto ;) Y... �qu� pasa si tenemos 2 bloques de memoria y queremos copiar todo lo que haya en uno al otro? Pues podr�amos hacer un FOR, pero hay una funci�n espec�fica para eso: Move. Move se usar�a as�: Move(Puntero_Fuente^, Puntero_Destino^, Tama�o); Cuando ya hayamos hecho todo lo que quer�amos con un bloque de memoria debemos liberarlo. Para eso usamos Freemem igual que si fuese GetMem: Freemem(Puntero, Tama�o). Hay que tener en cuenta que el puntero debe apuntar exactamente al mismo sitio que despu�s de hacer el GetMem. Es decir: si hemos usado alg�n INC o DEC con �l debemos asegurarnos que lo dejamos tal y como estaba antes de llamar a Freemem. Ahora supongamos que tenemos un puntero que apunta a una estructura y queremos reservar la memoria justa para que quepa esa estructura. Podemos contar los bytes que ocupa esa estructura (no estar�a mal para practicar ;) o podemos usar New en lugar de Getmem. A New s�lo hay que pasarle el puntero: New(Puntero); Y el equivalente a Freemem entonces ser� Dispose, que usaremos igual que New. Y ahora el punto m�s interesante. Antes de empezarlo os presento a NIL. NIL es una constante, pero no es una constante num�rica sino un puntero. Y �a d�nde apunta este puntero? En la ayuda dice que no apunta a ninguna parte. Y... aunque un puntero SIEMPRE apunta a alguna parte haremos como si fuese verdad que no apunta a nada. As� podemos decir que NIL es el puntero nulo. Ahora empecemos: declaramos un puntero as�: Type PEsctructura = ^Estructura; Estructura = record Nombre : String; Siguiente : PEstructura; End; Var Puntero : PEstructura; Bien... y reservamos memoria para el puntero: New(Puntero); En este momento ya tenemos un puntero apuntando a una estructura que consta de una cadena de caracteres y de otro puntero. Rellenamos el primer campo: Puntero^.Nombre := 'Pepito'; Y pedimos memoria para el segundo (ya que un puntero no podemos usarlo si no hemos pedido memoria para �l o le hemos hecho apuntar a alguna parte). New(Puntero^.Siguiente); Ahora el puntero Siguiente apunta a una estructura de datos que consta de 2 campos: una cadena de caracteres y un puntero. �os suena de algo? ;) Podemos volver a pedir memoria para el puntero de esta segunda estructura y luego pedir memoria para el puntero de la tercera, etc, etc... �Y qu� ventaja tiene esto? Pues que podemos irlo repitiendo todas las veces que queramos hasta que se nos acabe la memoria. En un array hay que definir el n�mero de elementos a la hora de escribir el programa, pero de esta manera podemos ir llenanado m�s y m�s elementos sin tener un l�mite prefijado. La pega ahora es... �C�mo se trabaja con esto? Pues bien, para dejarlo lo m�s claro posible os pongo un ejemplo sencillo: Type P2 = ^Estruc; Estruc = record Cadena : String; Siguiente : P2; End; Var Puntero, PAux : P2; Cadena : String; Begin WriteLn('Memoria libre: ',maxavail); WriteLn('Escribe nombres. (una linea en blanco para terminar)'); New(Puntero); PAux := Puntero; PAux^.Siguiente := Nil; Repeat ReadLn(Cadena); PAux^.Cadena := Cadena; if Cadena <> '' Then Begin New(PAux^.Siguiente); PAux := PAux^.Siguiente; PAux^.Siguiente := Nil; End; Until Cadena = ''; WriteLn; WriteLn('Has escrito:'); PAux := Puntero; While PAux^.Siguiente <> Nil do Begin WriteLn(Paux^.Cadena); Puntero := Paux; PAux := Paux^.Siguiente; Dispose(Puntero); End; Dispose(Paux); WriteLn('Memoria libre: ',maxavail); End.

CopyRight© 2003/2004, Diego Castillo. Todos los Derechos Reservados
Catamayo - Loja - Ecuador | Resoluci�n Minima 800x600
Estadisticas

Hosted by www.Geocities.ws

1