#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> char* test() { char* s = "Hello World"; size_t len = strlen(s); char* t = malloc(sizeof(char)*(len+1)); strcpy(t, s); free(t); return t; }; int main(void) { printf("%s\n", test()); return 0; };Me gustaría asignar y desasignar memoria dentro de la función. Probé este código y funciona, pero me pregunto:
main ?Una vez que llama free a un puntero, la memoria a la que apunta ya no es válida. Intentar utilizar un puntero a la memoria liberada desencadena un comportamiento indefinido . En este caso particular funcionó, pero no hay garantía de eso.
Si la función devuelve la memoria asignada, es responsabilidad de la persona que llama liberarla:
char* test() { char* s = "Hello World"; size_t len = strlen(s); char* t = malloc(sizeof(char)*(len+1)); strcpy(t, s); return t; }; int main(void) { char *t = test(); printf("%s\n", t); free(t); return 0; };malloc reserva memoria para su uso.
Libera free esa reserva. En general, no hace que la memoria desaparezca, no cambia el contenido de esa memoria y no altera el valor del puntero que contenía la dirección.
Después free(t) , los bytes de t aún contienen la misma configuración de bits que tenían antes de free . Luego return t; devuelve esos bits a la persona que llama.
Cuando main pasa esos bits a printf , printf los usa como la dirección para obtener los caracteres para %s . Como nada los ha cambiado, están impresos.
Es por eso que obtuviste el comportamiento que obtuviste con este programa. Sin embargo, nada de eso está garantizado. Una vez que se llamó a free con t , la reserva de memoria desapareció. Algo más en su programa podría haber usado esa memoria. Por ejemplo, printf podría haber asignado un búfer para su propio uso interno y eso podría haber usado la misma memoria.
En su mayor parte, malloc y free son solo métodos para coordinar el uso de la memoria, de modo que diferentes partes de su programa no intenten usar la misma memoria al mismo tiempo para diferentes propósitos. Cuando solo tiene una parte de su programa usando la memoria asignada, no hay otras partes de su programa que interfieran con eso. Entonces, la falta de coordinación no hizo que su programa fallara. Si tenía varias rutinas en su programa usando la memoria asignada, entonces es más probable que encuentre problemas al intentar usar la memoria después de que se haya liberado.
Además, una vez que se ha liberado la memoria, el compilador puede tratar un puntero como si no tuviera un valor fijo. La return t; no se requiere que la declaración devuelva ningún valor en particular.
No importa dónde free() un puntero. Una vez que está free() d, el puntero ya no es deferenciable (ni dentro ni fuera de la función donde estaba free() d)
El propósito de free() es devolver la memoria asignada con malloc() , por lo que la semántica es que, una vez que haya liberado una parte de la memoria, ya no se podrá utilizar.
En C, todos los parámetros se pasan por valor, por lo que free() no puede cambiar la expresión de valor que le pasó, y esta es la razón por la que el puntero no se cambia a un valor de puntero no válido (como NULL ) pero se le advierte que no más los usos del puntero se pueden hacer sin incurrir en un comportamiento indefinido.
Podría haber una solución en el diseño de free() y es pasar la variable de puntero que contiene el puntero por dirección, y así free() podría convertir el puntero en NULL . Pero esto no solo requiere más trabajo, sino que free() no sabe cuántas copias has hecho del valor que malloc() te dio... así que es imposible saber cuántas referencias tienes allí a ser anulado. Ese enfoque hace que sea imposible dar a free() la responsabilidad de anular la referencia a la memoria devuelta.
Entonces, si crees que gratis no convierte el puntero en NULL y por alguna extraña razón aún puedes usar la memoria devuelta, no lo hagas más, porque estarás cometiendo errores.
¡Estás aconsejado! :)