Tema destacado: Suscripción al boletín mensual de elhacker.net
Autor
|
Tema: Comprobar si libere o no memoria dinamica(SOLUCIONADO) (Leído 2,715 veces)
|
^Tifa^
Desconectado
Mensajes: 2.802
|
Hola. Tengo una pregunta que hacer, espero que no se la encuentren demasiado ignorante, pero es una duda Cuando vamos a reservar memoria dinamica en C procedemos siempre a hacer esto cierto :: variable = malloc(100*sizeof(variable)); if ( variable == 0 ) { puts("No se reservo la memoria requerida"); } Ok.. perfecto lo anterior se entiende.. entonces imaginemos que termina la aplicacion y libero : free(variable); Y despues de la sentencia anterior hago nuevamente esto :: if ( variable == 0 ) { puts("Memoria Liberada"); } else { puts("Aun tengo algo reservado"); } Aqui lo que ocurre es que siempre se me cumple la segunda secuencia la de "Aun tengo algo reservado" Y la variable en si no esta inicializada con ningun valor por ende me imprime una rara direccion virtual de memoria o codigo basura como dicen algunos... yo quiero saber, entonces como verifico realmente que dicha variable libero la memoria??? porque si evaluandola a cero o NULL comprobamos si reservo o no, no deberia darme como verdadero despues que la libero con free???
|
|
|
|
« Última modificación: 12 Noviembre 2008, 16:15 por ^TiFa^ »
|
En línea
|
|
|
|
ҒrεακΠιи∂
Desconectado
Mensajes: 184
|
Buenas
La funcion free() hace que esa porcion de memoria que reservaste vuelva al "pool" comun de la app, pero el puntero sigue apuntando a la misma porcion de memoria. Por eso es que siempre cumple la 2da condicion.
Solucion: Debajo de cada free(), asignale NULL al puntero
Salu2, FreakMind
|
|
|
|
|
En línea
|
Connoisseurs of C semantics find C++ inferior to ++C 
|
|
|
^Tifa^
Desconectado
Mensajes: 2.802
|
Entonces, si el puntero siempre va a apuntar a una direccion de memoria este jamas valdra cero o NULL cual sea el caso  Por ende si nunca vale cero o NULL desde su declaracion, es un poco corto usar esto :: puntero = malloc(1000*sizeof(puntero)); puntero == NULL ? puts("No se reservo") : puts("Se reservo"); Porque si nunca vale cero.. por ende como verifico realmente que asigno el espacio que el dice que asigno??? Y como verifico despues de usar free que realmente lo libero ??? Ok, puedo inicializar la variable asi puntero = 0; pero porque?? Si esto funciona asi, porque no se ha explico con anterioridad que se utilize asi?
|
|
|
|
|
En línea
|
|
|
|
Flakito81
Desconectado
Mensajes: 508
|
Lo sabes xq malloc te retorna el espacio adjudicado o NULL si no se pudo realizar la reserva de memoria.
|
|
|
|
|
En línea
|
|
|
|
^Tifa^
Desconectado
Mensajes: 2.802
|
Entonces si malloc funciona asi.. No puede free retornar NULL cuando se le llama??? Lo he hecho de varias maneras... y todavia llevo dudas, disculpen mi ignorancia. Pero quiero algo que cuando yo libere y lo compare con NULL o Cero me diga que si que efectivamente esta vacia. void funcion(int **numero);
int main() {
int *puntero;
fprintf(stdout, "Mi reserva es %d\n", puntero);
if((puntero = malloc(100)) == NULL ) { fprintf(stdout, "No se reservo la memoria\n"); } else { fprintf(stdout, "Se reservo la memoria\n"); }
fprintf(stdout, "Mi reserva es %d\n", puntero);
funcion(&puntero);
EXIT_SUCCESS; }
void funcion (int **numero) {
fprintf(stdout, "Mi reserva es %d\n", numero);
free(*numero);
if ( *numero == NULL || *numero == 0 ) { fprintf(stdout, "Se libero la memoria\n"); } else { fprintf(stdout, "No se libero\n"); }
fprintf(stdout, "Mi reserva es %d\n", numero);
}
|
|
|
|
« Última modificación: 11 Noviembre 2008, 22:45 por ^TiFa^ »
|
En línea
|
|
|
|
|
|
Anibal784
Desconectado
Mensajes: 762
Yo no la vote, pero me la tengo que aguantar igual
|
Lo que pasa es que tenés que confiar en que free libera la memoria, si no te gusta deberías empezar a ver cómo hace free para liberar o implementar por tu cuenta un free y ahí empezar a confiar en que el sistema operativo es el que libera realmente la memoria. free no puede poner a NULL tu puntero porque recibe por copia el puntero (si no me equivoco la firma de free sería void free(void*) ), si bien dentro de la función puede asignar NULL al puntero, cuando sale ese valor se pierde (es como cuando hacés una función que recibe 2 enteros, vos adentro podés jugar con esos enteros que tu variable original no se modifica). Ahora, supongamos que vos confiás en que free siempre libera la memoria y que hace bien su trabajo (es lo que deberías hacer) pero necesitás comprobar que el puntero sea NULL, lo que hacés es una función mao meno así: void liberar(void **ptr){ free(*ptr); *ptr = NULL; } pero es bastante, por decirlo así, al pedo hacer eso ya que no hace mucho, lo que lográs es que vos dentro de esa función podés hacer un montón de otras cosas, como guardar la posición de memoria liberada, o crearte una estructura y manejar conteo o extenderlas (siempre y cuando reimplemente mallo, calloc y realloc). En si free por si sóla no da ninguna certeza de que hizo realmente su trabajo (por lo menos lo que yo se).
|
|
|
|
|
En línea
|
El que llega sin que lo llamen, se va sin que lo echen. Vos no la votaste por eso la tenes adentro.
Lo fino no es lo tuyo, y a mi me chupa un huevo, soy argentino y no peronista, y eso es lo que realmente te molesta.
|
|
|
dooque
Desconectado
Mensajes: 149
|
pero es bastante, por decirlo así, al pedo hacer eso ya que no hace mucho, lo que lográs es que vos dentro de esa función podés hacer un montón de otras cosas, como guardar la posición de memoria liberada, o crearte una estructura y manejar conteo o extenderlas (siempre y cuando reimplemente mallo, calloc y realloc). En si free por si sóla no da ninguna certeza de que hizo realmente su trabajo (por lo menos lo que yo se).
Hola! Tengo dos cosas para acotar al tema! 1) Si no confias en "free()" ya es grave! jajajaja! MUY GRAVE! jajaja!! 2) Y la mas importante creo es que despues de hacer un "free()" de cualquier puntero es ALTAMENTE RECOMENDABLE asignarle NULL para que no quede apuntando a posiciones de memoria q mas adelante puedes pisar! he escuchado una tesis al respecto y he visto como sucumben grandes programas por causa de esto asi q como pequeña moraleja (o no tan pequeña) "Es bueno tener la costumbre q despues de liberar un puntero asignarlo a NULL"Otro efecto parecido tiene el hecho de declarar variables y no inicializarlas en el mismo momento! puedes romper facilmente programas asi y ni darte cuenta!! bueno ya flashie mucho!! Saludos!!
|
|
|
|
|
En línea
|
|
|
|
^Tifa^
Desconectado
Mensajes: 2.802
|
Hola nuevamente. 1) Si no confias en "free()" ya es grave! jajajaja! MUY GRAVE! jajaja!!
Entonces dame una razon 'logica' por la cual deba ciegamente confiar en el funcionamiento de esta y de malloc, porque yo expongo mis dudas y con ejemplos del porque estoy dudosa con estas 2 funciones... y aparentemente todos entienden mis ejemplos, pero nadie aun me ha dado una explicacion nociva y con ejemplos sobre porque debo simplemente 'confiar'. A lo mejor estoy en una ignorancia enorme, pero jamas he visto en ningun libro de C o C++ que se diga que despues de liberar memoria con free hay que asignarle NULL o cero a un puntero... Jamas he visto eso. Y si esto es asi, entonces la funcion free no es efectiva y no hace su trabajo que se supone que ha de hacer... o lo hace a otro nivel que desconozco ya sea a nivel mas profundo o de hardware que no puedo comprobar su efectividad con simples funciones tipo printf... Incluse fui mas lejos, intente asignarle cero con malloc a mi puntero : if ((puntero = malloc(0)) == 0) { printf("No se reservo"); } else { print("Se reservo"); } Y adivinen cual secuencia me responde? La segunda... "Se reservo". Sin embargo si asigno directamente cero a la variable puntero y lo igualo a cero ahi se cumple la primera : if ((puntero = 0)== 0) { printf("No se reservo"); } else { print("Se reservo"); } Aqui es efectiva la primera seleccion "No se reservo"... O malloc y free trabajan a un nivel mas bajo del normal y para comprobar de lleno lo que hacen no basta con usar printf o compararlas con cero o NULL, o todo este tiempo se ha estado enganando a todo el mundo con el funcionamiento de ambas funciones  A lo mejor alguien que conozca mucho sobre Assembly y C puede darme una explicacion mas logica sobre este hecho, porque aun tengo vacios en cuanto a esta relacion. Tampoco conozco a nadie que sin inicializar una variable a un valor la utilize en su programa para algo o sea seria ignorancia de cualquier programador hacer algo tipo : int variable; printf("El resultado es %d\n", (variable*5)); Ahi es una falla grave de la logia del programador, no del funcionamiento del lenguaje en si.
|
|
|
|
« Última modificación: 12 Noviembre 2008, 13:43 por ^TiFa^ »
|
En línea
|
|
|
|
Anibal784
Desconectado
Mensajes: 762
Yo no la vote, pero me la tengo que aguantar igual
|
free y [m|c|r]alloc son funciones del standard, eso significa que cada compilador hace su implementación de esas funciones, si no te agrada, no hace falta saber assembler sólo conocer cómo maneja tu sistema operativo la memoria y generar tu free y [m|c|r]alloc, ahora tampoco confiás en el manejo de memoria de tu sistema operativo, vas a tener que ensuciarte las manos y entrar a hacer tu propio manejador de memoria (cosa que en un sistema de código abierto ya es difícil, imaginate en uno que no proporciona el código). Dado la concepción de free es imposible que te retorne algo para que vos veas realmente si liberó o no la porción de memoria (a eso tenés que sumarle que el menejo de memoria dentro del sistema operativo es complicado, hasta el punto de hacerle creer al proceso que tiene 4Gb de memoria continua para el solo, cuando en realidad sólo tiene cargado 100k el resto está en el disco y lo más probable que esos 100k no sean continuos), es más si vos querés saber algo tenés que preguntarle al kernel y ¿adiviná qué? tenés que confiar en lo que el kernel te diga.
bueno, volviendo al tema, capaz que la implementación de free (tal como vos decís) no libera realmente la memoria, sino que guarda dentro de una estuctura información de que se pidió esa cantidad de memoria y que ahora está libre, entonces cuando vos pedís la misma cantidad se saltea al kernel y te retorna ese mismo espacio, a lo que quiero llegar es que lo que hace free a lo mejor no es liberar memoria sino que te dice no tenés más disponible esa memoria.
|
|
|
|
« Última modificación: 12 Noviembre 2008, 14:19 por Anibal784 »
|
En línea
|
El que llega sin que lo llamen, se va sin que lo echen. Vos no la votaste por eso la tenes adentro.
Lo fino no es lo tuyo, y a mi me chupa un huevo, soy argentino y no peronista, y eso es lo que realmente te molesta.
|
|
|
|
Karman
|
no entiendo mucho lo que quieres hacer pero: el resultado de malloc(0) no está completamente definido (en realidad si pero no está implementado de la misma forma en todos los compiladores), depende del compilador, en algunos casos retornará NULL, y en otros retornará un puntero a la cima (heap) de la memoria "solicitable". de todas formas hacer esto:
if ((puntero = 0)== 0)
es más que obvio su resultado, con respecto a lo de free, free está definida para ser VOID, de modo que no puede modificar el valor del puntero que libera, y la liberación queda en manos del SO, por lo que se realice con el espacio de memoria depende del SO, en algunos casos el espacio de memoria simplemente se marca como libre (no se libera) para que en futuras llamadas a malloc sea reutilizado.
como dato aclarativo, tanto malloc como free dependen del SO que se utilice, así que tendrías que buscar en la ayuda del SO que utilices para tener más información...
S2
|
|
|
|
|
En línea
|
|
|
|
dooque
Desconectado
Mensajes: 149
|
Aver... no si entiendo tus dudas pero a ver si esto te aclara un poco las cosas! Por un lado... C esta echo para manejar cosas de bajo niven sin usar asm, tiene las cosas basicas y necesarias y nada mas, todo el resto lo tiene q hacer el programador, esto tiene sus ventajas y desventajas... Una de esas cosas que tiene que hacer el programador es llevar la cuenta de la memoria que usa para que so programano tenga "Memory Leaks". Por el otro... Para el manejo dinamico de memoria C te brinda 4 funciones: void * calloc(size_t nmemb, size_t size);void * malloc(size_t size);void free(void *ptr);void * realloc(void *ptr, size_t size);Ver... http://www.poplog.org/docs/popdocs/pop11/unix/mallocBien! ahora... Entonces dame una razon 'logica' por la cual deba ciegamente confiar en el funcionamiento de esta y de malloc, porque yo expongo mis dudas y con ejemplos del porque estoy dudosa con estas 2 funciones... y aparentemente todos entienden mis ejemplos, pero nadie aun me ha dado una explicacion nociva y con ejemplos sobre porque debo simplemente 'confiar'.
Estas funciones (malloc/calloc) lo que hacen es hacer las llamadas al sistema correspondiente que le permiten al sistema operativo asignarle memoria a un proceso! po otro lado "free" hacela llamadaal sistema para devolverle memoria "que no va a usar" o "que ya no necesita" por decirlo de alguna manera! Si estas funciones no fueran confiebles habriamiles o millones de programas en C qno seria confiables (esto incluye a varios sistemas operativos) ademas esto implica q tampoco confias en las llamadas al kernel de tu SO, si ya no confias en esto pues cambia de SO jejeje! no digo q nunca puedan fallar, pero lo q digo es q si hay memoria disponible "malloc/calloc" te la van a dar y si llamas a "free" la memoria va a ser liberada. "maloc/calloc" pueden llegar a fallar (devolver NULLporque no hay memoria) con una mayor probabilidad que la de que "free" no libere la memoria! La memoria es un recurso escaso e importante y el kernel del sistema maneja muy bien y eficientemenete estas cosas.... o deberia hacerlo porlo menos! Si aun asi no te convences de que free no libera tu memoria puedes usar el programa "valgrind" (Solo para UNIX) que una pequeña maquina virtual que corre tu programa y lleva la cuenta de todo el manejo de memoria del proceso y mas, es una herramiente muy potente en UNIX para el manejo de "memory leaks" y errores de lectura y escritura en posiciones de memoria inadecuada q causan esos malditos "Segmentation Fault" (quien no ha visto uno de sos en C jajajajaja) si te lo bajas lo puedes corre asi: "valgrind ./mi_prg"tiene muchas opciones algunas piolas son: "valgrind --leak-check=full ./mi_prg" --> Sigue el rastro detodoslos punteros y te dice cuanta y donde esta la memoria que aun no has liberado! "valgrind -v ./mi_prg" --> Lo hace mas "verborragico" y hace quete tire mas detalles... lo corresy los ves! y haceslasprubas y veras q "free" simpre libera! A lo mejor estoy en una ignorancia enorme, pero jamas he visto en ningun libro de C o C++ que se diga que despues de liberar memoria con free hay que asignarle NULL o cero a un puntero... Jamas he visto eso. Y si esto es asi, entonces la funcion free no es efectiva y no hace su trabajo que se supone que ha de hacer... o lo hace a otro nivel que desconozco ya sea a nivel mas profundo o de hardware que no puedo comprobar su efectividad con simples funciones tipo printf...
Nuncavas a ver en un libro de Calgo asi, ni lo de inicializar variables ni sobre "coding style" ni nada q sean cosas del programador y no del lenguaje! esto es recomendabla solo porque los programadores tiene un 99% de probabilidad de cometer errores! hasta el mas groso de los grosos comete errores en programas grandes! con la practica esto se minimiza pero es inevitable, somo humanos, nos vamos a equivocar y mas vale estar prevenidos! Y te vuelvo a repetir "free" hace lo q debe hacer Y NADA MAS, solo libera la memoria, no hace otra cosa, elresto core porcuenta delprogramador, esto esasi para darle al programador la mayopr flixibilidad posible de q "haga lo q quiera", lasfunciones de C hacen lo minimoe indispensable y nada mas! por ellos suelen hacer bien o q hacen!! Incluse fui mas lejos, intente asignarle cero con malloc a mi puntero :
if ((puntero = malloc(0)) == 0) { printf("No se reservo"); } else { print("Se reservo"); }
Y adivinen cual secuencia me responde? La segunda... "Se reservo". Sin embargo si asigno directamente cero a la variable puntero y lo igualo a cero ahi se cumple la primera :
if ((puntero = 0)== 0) { printf("No se reservo"); } else { print("Se reservo"); }
Aqui es efectiva la primera seleccion "No se reservo"...
Que pasa aqui... en el primer ejemplo me juego la vida que no has inizializado la variable "puntero" a NULL cuando la declaraste (en caso de q si sorry), ya que un "p=malloc(0)" es equivalente a un "free(p)", esto implica q el valor de tu puntero no se modifica (o si?), ademas malloc devuelve NULL solo cuando NO HAY MEMORIA no cuando le pides 0 bytes! (asta donde se yo, esto es asi, me corrijan si estoy mal). Y con respecto al segundo ejemplito digo... es muy obvio jaja "if ((puntero = 0)== 0)" va a dar simpre vardadero, no hay nada de magia de punteros ahi. Otra cosa... los punteros deberias comparalos y asignarlos a NULL y no a 0 ya q almacenan direcciones de memoria y no enteros, digo.... ya se que "NULL == (void *)0" pero para algo esa no? Repito esto no esta en libros, son cosas de los programadores por el echo de q nos vivimos equivocando todo le tiempo! Espero haberte ayudado aunquesea un poquito... o a confundirte mas por lo menos jajajajajaja!!! Salu2!
|
|
|
|
|
En línea
|
|
|
|
dooque
Desconectado
Mensajes: 149
|
sorry! mientras escribia pusieron dos pos mas y se repite un poco lo q digo.. jejeje! para q veas q la mayoria piensa igual! jaja!! saludos!
|
|
|
|
|
En línea
|
|
|
|
EvilGoblin
Desconectado
Mensajes: 2.320
YO NO LA VOTE!
|
strlen(puntero); ? Mayormente yo limpio el buffer y para saber si esta limpio y liberado hago un Strlen(puntero) Suerte
|
|
|
|
|
En línea
|
Experimental Serial Lain [Linux User]
|
|
|
^Tifa^
Desconectado
Mensajes: 2.802
|
En resumen... Lo que ando solicitando es demasiado profundo que la unica respuesta que obtengo es 'debes confiar en que eso funciona asi'. Vaya, que motivador. No creo que si voy a reservar memoria dinamica en una variable deba inicializarla.. eso es absurdo, sobretodo si se supone que en esta se reservara memoria dinamica, por ende no puedo asignarle de antemano un valor sea cero o sea NULL. Algo como lo que dice EvolGoblin es lo que busco... pero para liberacion de memoria dinamica 
|
|
|
|
|
En línea
|
|
|
|
|
|