7.10.- Consideraciones avanzadas Alguien podria preguntarse ahora, ¨seria posible tener un puntero apuntando a un array y luego accesarlo mediante el puntero pero con la notacion de array? y la respuesta es si, se puede tener un puntero apuntando a cualquier cosa, los punteros a arrays se logran de la siguiente manera: 7.10.1.- punteros a arrays Luego de estudiar esta estructura el lector podra lograr las estructuras de dato mas complejas. PROGRAM PUNTERS; USES CRT; TYPE REGISTRO = RECORD NOMBRE : STRING; NUMEROS : INTEGER; END; PUNTER = ^PARRAY; PARRAY = ARRAY [0..20] OF REGISTRO; VAR PUNTERO : PUNTER; A : INTEGER; BEGIN CLRSCR; NEW (PUNTERO); FOR A := 1 TO 20 DO PUNTERO^ [A].EDAD := RANDOM (30); FOR A := 1 TO 20 DO WRITELN (PUNTERO^[A].EDAD); DISPOSE (PUNTERO); END. El problema con este metodo es que no podemos pasar sobre el pascal puesto que tenemos que declarar el array en la declaracion de tipos y es alli donde pascal nos impedira que sobrepasemos el limite de poco menos de 64k, pero esto no importa tanto si nos fijamos en la declaracion de variables, una variable tipo puntero ocupa 4 bytes y es todo lo que necesitamos para manipular una estructura de array de hasta 64k!! (sea o no con registros, lo maximo que permite esta estructura es poco menos de 64k). Obviamente este metodo sera extremadamente potente (y no es dificil) cuando se necesiten varias listas grandes pero en todo caso menores de 64k. 7.10.2.- El colmo de los punteros! Vimos en el ejemplo anterior como gastar pocos datos para tener acceso a estructuras grandes (por supuesto gastando espacio en el heap) pero el colmo de esto se logra teniendo un array de punteros, esta estructura es extremadamente potente. Veamos PROGRAM PARRAY; USES CRT; TYPE PUNTER = ^MATRIZ; { PUNTERO A MATRIZ } PINT = ^INTEGER; { PUNTERO A ENTERO } MATRIZ = ARRAY [0..100] OF PINT; {ARRAY DE PUNTEROS A ENTEROS} VAR PUNTERO : PUNTER; { PUNTERO A UN ARRAY DE PUNTEROS A ENTEROS } A : INTEGER; BEGIN CLRSCR; NEW (PUNTERO); { CREA PUNTERO A MATRIZ } FOR A := 1 TO 100 DO BEGIN NEW (PUNTERO^[A]); { CREA PUNTERO AL ENTERO } PUNTERO^[A]^ := RANDOM (20+A); END; FOR A := 1 TO 100 DO WRITE (PUNTERO^[A]^,' '); FOR A := 1 TO 100 DO {ELIMINA PUNTEROS} DISPOSE (PUNTERO^[A]); DISPOSE (PUNTERO); { ELIMINA PUNTERO A ARRAY DE PUNTEROS } END. Se necesita tener un puntero al array de punteros. En este caso se trata de un array de punteros a enteros. Se preguntara para que molestarse en crear esto si se gastan 4 bytes por cada puntero a un entero que se mantenga siendo estos de 2 bytes, y esta es una pregunta inteligente, pero tenga en cuenta que esta estructura es REMOVIBLE cuando se desee, asi aunque cada entero ocupe 6 bytes (4 bytes por el puntero y 2 por el entero mismo) en realidad esto solo es temporal. Pudiendose liberar de ese gasto en cualquier momento (algo muy deseable cuando ya no se necesite la variable) el resultado es tener un array dinamico, otra ventaja la veremos en un momento. En fin casi llegamos al ultimo nivel, tenemos un array que es casi polimorfico (es polimorfico cuando se usa punteros sin tipo, alli podremos tener cualquier tipo de dato en cada elemento de nuestro array de punteros, pero por ahora todos los punteros apuntan al mismo tipo de dato), llegamos a la irresistible tentacion de considerar otra vez un array de punteros a registros pero esta vez con un puntero al array para mantener la estructura. Nuestro suenio se convierte en realidad de la siguiente manera: PROGRAM PARRAYREG; USES CRT; CONST ELE = 800; TYPE REGISTRO = RECORD { UN REGISTRO COMUN Y CORRIENTE } NOMBRE : STRING; NUMERO : INTEGER; END; PREG = ^REGISTRO; { UN PUNTERO A NUESTRO REGISTRO } MATRIZ = ARRAY [0..ELE] OF PREG; {UN ARRAY DE PUNTEROS } PUNTER = ^MATRIZ; VAR PUNTERO : PUNTER; {PUNTERO AL ARRAY DE PUNTEROS A REGISTROS} A : INTEGER; BEGIN CLRSCR; NEW (PUNTERO); { CREACION DEL PUNTERO AL ARRAY } FOR A := 1 TO ELE DO BEGIN NEW (PUNTERO^[A]); {CREACION DE UN PUNTERO AL REGISTRO } PUNTERO^[A]^.NUMERO := RANDOM (200+A); END; FOR A := 1 TO ELE DO WRITELN (A,'.- ',PUNTERO^[A]^.NUMERO); FOR A := 1 TO ELE DO DISPOSE (PUNTERO^[A]); {ELIMINA PUNTERO } DISPOSE (PUNTERO); { ELIMINA PUNTERO AL ARRAY } END. Notese como esta definido nuestro registro, 800 elementos de un tipo string de 256 bytes y un tipo integer de 2 bytes o sea resulta 800 * 258 = 206,400 con lo cual hemos sobrepasado muy facilmente el limite de los temibles 64k lo cual es un maravilla por cierto, pero hay que considerar las dificultades que se crean trabajando con los punteros, con estos se pierde un poco la proteccion maternal de turbo pascal para la comprobacion de tipos y rangos, una asignacion incorrecta y zas! volo el ordenador, ademas, hay que comprobar el heap con maxavail (o instalar una funcion de error para controlar el heap) para ver si es posible la creacion de la variable dinamica, tambien en este caso hay que tener cuidado con la fragmentacion del heap (a cada new debe corresponderle un dispose). .