Uso de punteros como array dinámico para novatos.

Started by Drumpi, December 02, 2009, 12:51:50 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Drumpi

Usar punteros como array dinámico es sencillo.
¿Que qué es esto? bueno, cuando declaramos un vector, este tiene un tamaño fijo, y más de uno se ha perguntado si no se pueden definir en base a una variable. Pues vamos a aprender cómo hacer uno de estos, y que se pueda cambiar de tamaño en plena ejecución del juego.

Primero debes declarar un puntero, para ello usamos la palabra POINTER seguido del nombre que queramos:

POINTER mi_puntero;

Pero seguramente quieras usar un tipo de datos en cada posición, quizás un BYTE porque no vas a usar más de 256 valores, quizás INT porque vayas a usar números negativos, o incluso un tipo que te hayas creado tu. Para indicárselo a Bennu, hay que añadírselo antes de la palabra POINTER:

int POINTER mi_puntero;

Un ejemplo creando un tipo nuevo llamado coordenadas:

TYPE coordenadas
INT x,y,z;
END
coordenadas POINTER mi_puntero;

Bien ya tenemos un puntero, pero inicialmente está vacío, no se puede usar. Para ello primero hay que reservar espacio en memoria, cualquiera.

mi_puntero=alloc(5);

Con esto reservamos 5 bytes, lo cual no es correcto para usar INTs, pues cada INT requiere 4 bytes ¿cómo reservar espacio para 5 variables del tipo INT?

mi_puntero=alloc(5*sizeof(INT));

¿Y para 7 variables de tipo coordenadas?

mi_puntero=alloc(7*sizeof(coordenadas));

(Que alguien me corrija si me equivoco, pero creo que con Bennu ya no es necesario especificar el tamaño del tipo de variable ¿o sigue siendo así?)

Bien, ya tenemos un array de X posiciones. Lo bueno de este método es que ahora podemos trabajar con mi_puntero como si fuera un array normal:

INT variable
variable=mi_puntero[3];  //guardamos en "variable" el valor que hubiese en la cuarta posición

coordenadas variable;
variable=mi_puntero[5];  //guardamos en "variable" LOS VALORES de la estructura que hubiese en la sexta posición
mi_puntero[4].x=3; //guardamos 3 en el campo x de la quinta variable.

OJO: cuando trabajamos con punteros, la memoria que reservemos NO SE PONE A CERO, puede valer cualquier valor inicialmente, es importantísimo tenerlo en cuenta.
Supongamos que ahora queremos cambiar el tamaño, no hay problema, usamos REALLOC en lugar de ALLOC:

mi_puntero=REALLOC(mi_puntero, 1100*sizeof(INT));

Esta vez necesitamos indicarle a REALLOC qué puntero queremos redimensionar, y es importante volver a hacer la asignación, porque es muy probable que la zona de memoria haya cambiado de sitio.
Cuando acabemos, es IMPRESCINDIBLE liberar la memoria que no estemos usando, porque puede que esta quede en el sistema como ocupada, aun después de haber cerrado el programa, esto no es Java, amigos ;D Para ello, usamos la función FREE:

FREE(mi_puntero);

Y ya está ¿fácil? pues si, pero peligroso: ya he avisado del peligro de no usar FREE, pero tanto o más es acceder a una zona de memoria que no existe (por ejemplo, a mi_puntero[7000]), porque es muy probable que se nos salga del programa sin dar ningún aviso (quizás un segmentation fault) y la cosa se queda ahí, pero en raras ocasiones puede que no nos diga nada y nos metamos en zonas de memoria que no debemos tocar, CUIDADO.

Para más dudas, acceder a los lugares habituales (el manual de OSK ;D).
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

DjSonyk

Vale,ya veo lo que hacia mal,muchas gracias Drumpi,ahi van 2 karmas uno por todas las molestias y otro por toda la ayuda ;P:

Windgate

Toma tu karma, llevaba tiempo dando vueltas a este tema e incluso tengo por ahí código preparado con un #define para hacer un array dinámico con un tipo de dato "cualquiera" que puede definirse en la sentencia #define.

Me refiero a un módulo que tenga las operaciones básicas de vector:

Nuevo vector
Añadir elemento
Quitar elemento de la posición N
Elimintar vector

Espero que salga material interesante de este hilo, ya me he encontrado con varios casos prácticos que piden a gritos vectores dinámicos, especialmente en juegos de estrategia que es un tema que apenas hemos tocado en el foro :P

Besitos Drumpi :-* xD
Iván García Subero. Programador, profesor de informática, monitor de actividades culturales y presidente de TRINIT Asociación de Informáticos de Zaragoza. http://trinit.es

Windgate

Bien, ahora he podido leer con más detenimiento, te voy a criticar hasta la humillación (Broma :P):

Quote(Que alguien me corrija si me equivoco, pero creo que con Bennu ya no es necesario especificar el tamaño del tipo de variable ¿o sigue siendo así?)

sizeof funciona perfectamente, así debería hacerse.

QuoteINT variable
variable=mi_puntero[3];

mi_puntero almacena datos de tipo coordenada, y estás asignando al entero variable un dato de tipo coordenada... ¿No sería más limpio hacer que variable fuese de tipo coordenada también?

Me parece bien el mini-tutorial que has creado, pero definitivamente no me sirve, el coste de realloc a cada vez que el vector cambia de tamaño es muy elevado. Yo lo que busco es una lista enlazada, en la que los nuevos elementos añadidos crean nuevos nodos y los elementos borrados liberan nodos, volviendo a enlazar la lista donde se rompió.

Hace un tiempo empecé con algo así, pero como tantas otras cosas no lo terminé... Supongo que cuando realmente me haga falta retomaré el trabajo.
Iván García Subero. Programador, profesor de informática, monitor de actividades culturales y presidente de TRINIT Asociación de Informáticos de Zaragoza. http://trinit.es

DjSonyk

Wind creo entenderte que lo que quieres es una "Lista aninada",tambien estan las pilas(LIFO) y las colas (FIFO)....
Pero por tus explicaciones entiendo que lo que necesitas es una lista...No creo que sea muy dificil de imprementar yo tengo aun los libros del curso de JAVA que hice y vienen muy bien explicado,viene un ejercicio de prueba cuando tenga unos minutos le porto a Bennu...

Windgate

Yo también tengo ejemplos por ahí, pero no lo completé en su día porque quería hacerlo con #define para que funcionase con cualquier tipo de dato, especificándolo en el define.

Si te me adelantas te doy mi karmín xD
Iván García Subero. Programador, profesor de informática, monitor de actividades culturales y presidente de TRINIT Asociación de Informáticos de Zaragoza. http://trinit.es

Drumpi

Quote from: Windgate on December 02, 2009, 01:55:56 PM
Bien, ahora he podido leer con más detenimiento, te voy a criticar hasta la humillación (Broma :P):

Quote(Que alguien me corrija si me equivoco, pero creo que con Bennu ya no es necesario especificar el tamaño del tipo de variable ¿o sigue siendo así?)

sizeof funciona perfectamente, así debería hacerse.

No, yo lo decía porque era posible que no se necesitase el sizeof, que al decirle "5", Bennu ya reservaba 5 posiciones del tamaño que sea el tipo al que apunta el puntero.

Quote from: Windgate on December 02, 2009, 01:55:56 PM
QuoteINT variable
variable=mi_puntero[3];

mi_puntero almacena datos de tipo coordenada, y estás asignando al entero variable un dato de tipo coordenada... ¿No sería más limpio hacer que variable fuese de tipo coordenada también?

No, en ese ejemplo no he dicho el tipo de datos que almacena mi_puntero, quizás debí haber explicado mejor que en este caso hacía referencia al primer ejemplo de todos los que hay en el mini-tuto, o haber usado nombres distintos.
Pero al menos veo que habeis cogido la idea :D

Quote from: Windgate on December 02, 2009, 01:55:56 PMMe parece bien el mini-tutorial que has creado, pero definitivamente no me sirve, el coste de realloc a cada vez que el vector cambia de tamaño es muy elevado. Yo lo que busco es una lista enlazada, en la que los nuevos elementos añadidos crean nuevos nodos y los elementos borrados liberan nodos, volviendo a enlazar la lista donde se rompió.

Hace un tiempo empecé con algo así, pero como tantas otras cosas no lo terminé... Supongo que cuando realmente me haga falta retomaré el trabajo.

El tuto es por una duda que me planteó DjSonyk. Obviamente el uso de realloc se come las últimas posiciones, si lo que quieres es reorganizarlo internamente, te toca crear una lista enlazada. No es complicado, pero si laborioso (menos mal que los tipos definidos pueden ahorrar mucho trabajo de adaptación a otros tipos de nodos si se hace bien).
Si lo veis necesario, y la guia de Osk no os parece suficiente, puedo probar a hacer otro mini-tuto al respecto (y luego, s alguien quiere, pues que los ponga en la wiki, que no me aclaro con su "código").
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

DjSonyk

Si la duda era mia que no sabia como declarar los punteros,hasta tal punto que escribia aberraciones..... con lo simple que.... ^^

Nada ahora estoy pegandome como pasar los datos de la memoria dinamica a un fichero xD,por ahora tengo una chapuza pero no me gusta...en fins llevo un par de dias que madre de dios hermoso....

Windgate

DjSonik, ¿No debería valer con un fwrite y el nombre del vector?

Hace poco se dijo en un hilo, que Bennu escribe los datos del vector, sea de 1, 10 o 1000 "celdas" el jodido...
Iván García Subero. Programador, profesor de informática, monitor de actividades culturales y presidente de TRINIT Asociación de Informáticos de Zaragoza. http://trinit.es

DjSonyk

#9
¿No me fastidies que es tan facil?voy aprobar


EDIT : nonono, no lo guarda ,vamos al menos que un array de 64*64*3 ocupe 4 bytes XD,creo que guarda el puntero....Lo que quiero es volcar los datos de la memoria donde tengo guardado los valores a un archivo....Aun asi me gusta muy poco tener Type con 3 valores,estaba mejor como lo tenia antes aunque no se pudiera modificar en ejecucucción, era una strucutura filay y filax ,y ya me guardaba el codido,ahora es &celda[0].x; &celda[0].y; &celda[0].id;
pufff!!!
EDIT 2: Para guardalo uso GuardaX=&celda[n].X;GuardaY=&Celda[n].y;Guardaid=&Celda[n].id;con un bucle y tres fwrite ().....

Drumpi

#10
Lo habría escrito hace un par de horas, pero el servidor se puso en modo mantenimiento y me dejó con la palabra en la boca (o con el texto en el portapapeles, más bien ;D)

id_fich=FOPEN("datos.bin",O_WRITE);
FOR (n=0;n<=max_datos;n++)
FWRITE(id_fich, mi_puntero[n]);
END
FCLOSE(id_fich);

Esto es lo más simple, ahora tu le vas añadiendo toda la complicación que te de la gana ^^U

PD: a tu método creo que le sobra el & de delante, tanto a la hora de escribir le array, como a usar &celda[0].x, el [] ya indica que nos referimos al contenido (como poner * al principio).
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

DjSonyk

 :o
toda la tarde bucando la solución y aparece drumpi.........
aun asi tengo problemas con la carga,asi que no se si de todas formas lo estaba haciendo mal o lo cargo mal....... dios que asquito esto de la memoria dinamica.....y veo que aun sigo sin cojerlo,cuando mas creo a ver entendido como funciona mas cuenta me doy que no se como funciona...menos mal que por ejemplo tenemos el garbage collection y lo hace solito al menos enque maneja la memoria dinamica auto....gracias de nuevo

Drumpi

Llevo años tras el título de "Master de los Ficheros", pero con todos los cambios que ha habido en Bennu he pasado de experto a simple "aficionado" ;D
Tu di que problemas tienes con la carga y trataremos de ayudar, pero para el tema de leer/escribir en ficheros suelo usar tres variables auxiliares con FREAD/FWRITE:
BYTE dato_b;
WORD dato_w;
INT dato_i;
Se que no es eficiente ni recomendable, pero así evitas cualquier problema ligado al mal reconocimiento de los tipos. Mas adelante ya te atreves a más.

¿Garbage collection? ¿Eso existe?
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)

DjSonyk

Garbage collection o Colector de Basura ,existe o se llama asi en JAVA se puede usar con System.gc(),lo he recordado viendo lo de las listas aninadas a ver como le hacia un ejemplo a Wind y estaba ahi escrito...

A ver lo e gradado como me as dicho pero al leer me sale por say(),numero muy grandes,apenas uso del 1 al 10 para colocar los procesos,lo que me e fijado que salen con una distancia de 12 osea por ejemplo, 3000,3012,3024,ect,creo que se refiere a la direcion de memoria,te adjunto el codigo que creo que sera por eso no me va...
declaracion de datos:
TYPE Celda
   INT X,Y,Grafico;
END
Celda POINTER Celdas;
abrir fichero

Celdas=Alloc(3072*sizeof(Celdas));
id_fich=FOPEN("dat.dat",O_READ);
FOR (contador10=0;contador10<=3072;contador10++)
   Fread(id_fich, Celdas[contador10]);      
END
FCLOSE(id_fich);

Drumpi

Supongo que el SAY lo haces así:
FOR (contador10=0;contador10<3072;contador10++)  //<- OJO, la posición 3072 no existe ¿o si?
SAY(itoa(celdas[contador10].X));
SAY(itoa(celdas[contador10].Y));
SAY(itoa(celdas[contador10].Grafico));
END

Si no, prueba primero a grabar un "dat.dat" con valores que conozcas (por ejemplo, del 0 al 9) a ver si lo lee bien (o usa un lector hexadecimal para comprobarlo, son muy socorridos).
Hala, como con 1001 procesos sólo va a 9 FPS, vamos a meterle 32 veces más, a ver si revienta.
(Drumpi epic moment)