¿Cómo funciona free ()?

#include  #include  #include  int main () { int * ptr; printf("before malloc pointer is :%p \n",ptr); printf("before malloc valu is :%d \n",*ptr); ptr = malloc(sizeof(int)); printf("after malloc pointer is %p \n",ptr); printf("after malloc valu is :%d \n",*ptr); int jig=32; *ptr = jig; printf("after assignment valu is : %d\n",*ptr); free(ptr); printf("after free %p \n",ptr); // after free pointer holds sane address then printf("after fee is %d\n",*ptr); // why it coudnt print that??? return 0; } 

la salida es:

  before malloc pointer is :0x6edff4 before malloc valu is :7265660 after malloc pointer is 0x9a52008 after malloc valu is :0 after assignment valu is : 32 after free 0x9a52008 after fee is 0 

después de que el puntero fijo libre contiene la dirección de esa memoria, entonces ¿por qué no podemos imprimir el valor de esa memoria?

¿Qué hace free ()?

¿Solo hace que toda la memoria sea 0 .. ??

después de que el puntero fijo libre contiene la dirección de esa memoria, entonces ¿por qué no podemos imprimir el valor de esa memoria?

Porque la memoria ya no te pertenece. Lo liberas, lo que significa que el sistema operativo puede reutilizarlo como mejor le parezca, donde sea que necesite asignar más memoria. Ya no lo posee, por lo tanto, ya no tiene ningún negocio mirando el valor de los datos almacenados en esa memoria.

Tenga en cuenta también que:

 int *ptr; ... printf("Before malloc valu is :%d\n", *ptr); 

es igualmente inválido. ptr tiene un valor de basura y puede apuntar a cualquier parte. La anulación de la referencia no está garantizada como una ubicación de memoria a la que pueda acceder.

Ambos de estos casos invocan un comportamiento indefinido , lo que significa que la norma dice “NO HAGA ESTO”, y si ignora la norma, su código se romperá de maneras horribles cada vez que su jefe esté mirando.

¿Qué hace free ()?

¿Solo hace que toda la memoria sea 0 .. ??

No, no necesariamente. El sistema operativo a menudo reduce a cero la memoria no utilizada en segundo plano para que las llamadas a calloc más rápidas, pero de forma free solo le dice al sistema operativo “He terminado con esta memoria, haga lo que sea necesario con ella”. El sistema operativo generalmente actualiza algunos datos de mantenimiento para indicar que el bloque de memoria ya no es propiedad de un proceso, de modo que una llamada posterior a malloc puede usarlo si es necesario.

Lo interesante de malloc() y free() es que en realidad no cambian la memoria que te dan, simplemente cambian la forma en que se “piensa”.

Cuando llamas a malloc (), un segmento de memoria es elegido y dedicado para ser tuyo. Si bien es tuyo puedes usarlo como quieras.

Cuando hayas terminado con eso, lo free() , pero sigue ahí. Sigue siendo la misma memoria [1], simplemente ya no se considera “la tuya”. Así que alguien más podría estar usándolo.

[1] Supuse que con direccionamiento virtual esto podría no ser siempre cierto. Pero suele ser cierto.

free devuelve la memoria al sistema. Es la operación socia a malloc . Todo el bloque de memoria que asigne con malloc debe devolverse al sistema llamando free . Después de que llames free ya no puedes acceder a esa memoria.

Por lo general, se considera prudente establecer el puntero en NULL después de que haya llamado free , al menos en comstackciones de depuración, de modo que pueda estar seguro de que se generará un error si más tarde intenta desreferenciar el puntero por error.


Entonces, ¿por qué todavía puedes acceder a la memoria que se ha liberado? Bueno, no puedes hacerlo de manera confiable. Da la casualidad de que la implementación de la mayoría de los sistemas de administración de memoria significa que a veces se puede salir con tales abusos. Muchos administradores de memoria asignan grandes bloques de memoria de los sistemas operativos y luego, a su vez, asignan pequeños subbloques a la aplicación. Cuando llama free , el asignador devuelve ese bloque a su grupo de memoria disponible, pero no necesariamente devuelve la memoria al sistema operativo, ya que las rutinas de asignación de memoria del sistema operativo suelen ser caras. Por lo tanto, el acceso a él aún puede parecer que funciona, porque la memoria aún está asignada en su proceso. Es solo que ahora es propiedad del administrador de memoria en lugar de su aplicación. Algo así te está pasando aquí.

Por supuesto, a veces no te librarás de abusos como este, lo más probable es que una vez que hayas implementado tu software en la máquina de tu cliente más importante.

Normalmente, el administrador de memoria tendrá algo así como una lista vinculada de bloques libres que se utilizan para satisfacer las asignaciones posteriores.

Aquí hay una implementación mínima que escribí hace varios años. Realmente no está destinado (o es adecuado) para un uso serio, pero da al menos una idea general de una forma de administrar un montón:

 #include  typedef struct node { size_t size; struct node *next; } node; node *free_list; static void *split_end(node *block, size_t new_size) { size_t difference = block->size - new_size; node *temp = (node *)((char *)block + difference); temp->size = new_size; block->size = difference; return (void *)((size_t *)temp+1); } static void *split_begin(node *block, size_t new_size) { size_t difference = block->size-new_size; node *temp = (node *)((char *)block + new_size); temp->size = difference; temp->next = free_list; free_list = temp; return block; } void b_init(void *block, size_t block_size) { ((node *)block)->size = block_size - sizeof(node); ((node *)block)->next = NULL; free_list = block; } void b_free(void *block) { node *b = (node *)((size_t *)block -1); b->next = free_list; free_list = b; } void *b_malloc(size_t size) { node *temp, **ptr; size_t larger = size+sizeof(node); size += sizeof(size_t); for ( ptr = &free_list; NULL != ptr; ptr = &((*ptr)->next)) { if ((*ptr)->size >= size) { if ( (*ptr)->size <= larger) { temp = (*ptr); (*ptr) = (*ptr)->next; return (void *)((size_t *)temp + 1); } else return split_end(*ptr, size); } } return NULL; } void *b_realloc(void *block, size_t new_size) { node *b = (node *)((char *)block - sizeof(size_t)); char *temp; size_t i, size; if ( new_size == 0) { b_free(block); return NULL; } new_size += sizeof(size_t); size = b->size; if ( new_size size >= new_size+sizeof(node *) ) return split_begin(b, new_size); if ( b->size >= new_size) return b; temp = b_malloc(new_size); if ( NULL == temp) return NULL; for ( i=0; i