Punteros anidados

Started by warrior_rockk, December 13, 2016, 05:08:58 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

warrior_rockk

Supongamos el siguiente código:




Type _tipo
        int codigo;
byte* elementos;
end;


global
struct str
byte dato;
_tipo* tipos;
end;
end;



Lo que tenemos es una estructura con un puntero a un tipo definido por el usuario que, a su vez, ese tipo tiene un puntero de bytes. Para iniciar el puntero de tipos haríamos lo siguiente:



str.tipos = calloc(5,sizeof(_tipo));



Y para iniciar el puntero del tipo, tendríamos que recorrer las 5 posiciones de tipo e ir asignándolas:



for (i=0;i<5;i++)
      str.tipos[i].elementos = calloc(10,sizeof(byte));
end;



Hasta aquí todo correcto. Habríamos asignado en la estructura str, un array de 5 tipos con 10 elementos tipo byte dentro cada uno.


Mi duda ahora es a la hora de liberar la memoria. Sospecho que free(str.tipos) no es suficiente ya que, un puntero es un elemento que contiene un bloque de memoria, esto es, apunta a una dirección de memoria de inicio y de un tamaño determinado. A la hora de crear el puntero de tipos, como dentro del TYPE tipo hay un puntero, el sistema no sabe el tamaño que tendrá que reservar. De hecho, reserva 4 bytes por puntero porque es lo que ocupa una dirección de memoria. Pero esa dirección de memoria puede extenderse desconocidamente porque todavía no ha sido asignada.
Mi duda es, a la hora de llamar a free, ¿se encarga de leer los punteros dentro del bloque de memoria y liberar a su vez las zonas de memoria anidadas¿ ¿o tendríamos que recorrer de nivel inferior a superior liberando los elementos de cada tipo para luego liberar tipo?


Espero que se me haya entendido...

SplinterGU

#1
recorre elementos

pero presta atencion que con "_tipo*    tipos;" no estas declarando una variable _tipo, sino que es un puntero a ella y esa variable la tenes que crear con malloc.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

warrior_rockk

Pero, ¿la diferencia entre malloc (alias alloc) y calloc no es que ésta última inicializa con ceros las posiciones de memoria, con lo que es más optima para usos como array?

SplinterGU

Quote from: warrior_rockk on December 13, 2016, 06:38:44 PM
Pero, ¿la diferencia entre malloc (alias alloc) y calloc no es que ésta última inicializa con ceros las posiciones de memoria, con lo que es más optima para usos como array?

claro, es mas lenta, porque inicializa con 0, pero si, cuando dije malloc me referia a *alloc... pero si, es la idea.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Drumpi

Anda, y yo siempre he usado alloc para crear los punteros, no había visto calloc ^^U
De todas formas, gracias a alloc, siempre encuentro los errores de punteros, porque el programa empieza a hacerme cosas raras, a darme errores y a mostrarme valores fuera de escala. Si estuvieran a cero, lo mismo pasaría alguno por alto :D

Pero sí, siempre hay que liberar memoria de dentro hacia afuera. Más que nada es una buena práctica, porque nunca sabes si el próximo lenguaje que te encuentres hará la liberación de memoria de forma automática o no. Siempre es mejor prevenir.
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)

SplinterGU

drumpi, por el contrario, calloc sirve para tener las cosas mas ordenadas, porque los punteros no allocados dentro de un struct alocado con calloc, valdran NULL, entonces, incluso no tendrias cuelgues o cosas raras por hacer free de NULL, ya que free ignora los NULL, pero no ignora los BASURA...
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

warrior_rockk

Quote from: Drumpi on December 14, 2016, 01:35:45 AM
Pero sí, siempre hay que liberar memoria de dentro hacia afuera. Más que nada es una buena práctica, porque nunca sabes si el próximo lenguaje que te encuentres hará la liberación de memoria de forma automática o no. Siempre es mejor prevenir.


¿Seguro? Lo digo porque, si el lenguaje que utilizas ya recorre los elementos y posibles punteros anidados y los libera, liberando tu mismo de dentro a fuera provocas el liberar 2 veces una posición de memoria que ya estaba libre con lo que, si se ocupó por otro proceso (aunque no sea de tu aplicación), puedes provocar resultados inesperados...

Yawin

Si el lenguaje es suficientemente listo como para liberar él solito los punteros, no tendrá problemas si tú has liberado alguno. Será lo suficientemente listo como para saber que lo que apunta a NULL no hay que liberarlo.
Sigue el desarrollo de mi motor RPG: https://www.youtube.com/watch?v=TbsDq3RHU7g

process main()
       begin
           loop
               pedo();
               frame;
            end
       end

Drumpi

Quote from: SplinterGU on December 14, 2016, 04:37:32 AM
drumpi, por el contrario, calloc sirve para tener las cosas mas ordenadas, porque los punteros no allocados dentro de un struct alocado con calloc, valdran NULL, entonces, incluso no tendrias cuelgues o cosas raras por hacer free de NULL, ya que free ignora los NULL, pero no ignora los BASURA...

No, si lo digo por eso :D
Si uso calloc, es posible que si hago puntero -> sig, y puntero vale NULL, el SO se lo traga, porque NULL puede ser una dirección válida que no suele dar error. Si vale otra cosa es posible que se meta en el espacio de otro programa y aparezca un segmentation fault o que se modifiquen valores aleatorios, y así detecto acceso a punteros que están mal.
Pero sí, usando CALLOC me ahorraría la mitad de los problemas que me suelen dar :D

Quote from: warrior_rockk on December 14, 2016, 07:28:47 AM
Quote from: Drumpi on December 14, 2016, 01:35:45 AM
Pero sí, siempre hay que liberar memoria de dentro hacia afuera. Más que nada es una buena práctica, porque nunca sabes si el próximo lenguaje que te encuentres hará la liberación de memoria de forma automática o no. Siempre es mejor prevenir.


¿Seguro? Lo digo porque, si el lenguaje que utilizas ya recorre los elementos y posibles punteros anidados y los libera, liberando tu mismo de dentro a fuera provocas el liberar 2 veces una posición de memoria que ya estaba libre con lo que, si se ocupó por otro proceso (aunque no sea de tu aplicación), puedes provocar resultados inesperados...

Exacto, lo que dice Yawin: si liberas un puntero, el código debería saberlo.
Pero ahora te pongo en el otro caso: te acostumbras a Java, donde no hay que liberar punteros... o que es tan sencillo como poner una variable a 0, y la clase a la que apuntaba y sus hijas desaparecen sin dejar rastro, liberando todos los punteros, memoria etc...
Y al día siguiente te pones a programar en C, y liberas la memoria de una estructra y no de los punteros de las subestructuras... Lo mismo no da error, pero estás ocupando memoria que no vas a poder usar hasta que se cierre el programa.

Los punteros son algo muy delicado, hay que saber lo que se hace al 100%, y es por lo que tanto novatos como programadores de alto nivel (y algún que otro perezoso) no les gusta programarlos e intentan evitarlos a toda costa... y son de las cosas más útiles que vas a ver para ahorro de memoria, paso de parámetros e incluso para ejecutar unas funciones o DLLs según si existen o no :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)

warrior_rockk

Me parece buena práctica no dar nada por hecho en los lenguajes y asegurarse de todo mediante código. Lo que sí es importante recordar, para programación en Bennu, no olvidar poner el puntero a NULL tras hacer free, o si que tendríamos problemas por "reliberar" punteros. Puede parecer obvio pero , hasta hace poco, pensaba que con free era bastante y ponía el puntero a NULL y no era asi... :P