con - strcpy_s c++ para que sirve
strdup y pérdida de memoria (3)
Considere la siguiente definición para strdup
:
#include <string.h>
char *strdup(const char *string);
strdup
reserva espacio de almacenamiento para una copia destring
llamando amalloc
. Se espera que el argumento de cadena a esta función contenga un carácternull
(/0
) que marca el final de la cadena. Recuerde liberar el almacenamiento reservado con la llamada astrdup
.
Debe free
la cadena usted mismo.
¿Strdup asigna otra zona de memoria y crea otro puntero cada vez?
Por ejemplo: ¿el siguiente código da como resultado una pérdida de memoria?
void x(char** d, char* s){
*d = strdup(s);
}
int main(){
char* test = NULL;
x(&test, "abcd");
x(&test, "etc");
return 0;
}
Sí, asigna memoria y fugas si no la liberas. Desde la página man :
La función strdup () devuelve un puntero a una nueva cadena que es un duplicado de la cadena s. La memoria para la nueva cuerda se obtiene con malloc (3) y se puede liberar con free (3) .
new_s = strdup(s)
es esencialmente equivalente a:
new_s = malloc(strlen(s)+1);
strcpy(new_s, s);
Sí, el programa pierde memoria porque asigna objetos y luego pierde referencias a ellos.
La primera vez que esto sucede está en la línea:
x(&test, "etc");
La test
variable contiene la única copia de un puntero que se asignó en una llamada previa a x
. La nueva llamada a x
sobrescribe ese puntero. En ese punto, el puntero gotea.
Esto es lo que significa perder memoria: perder todas las referencias a una pieza de almacenamiento existente asignada dinámicamente .
La segunda fuga ocurre cuando la función main
regresa. En ese punto, la variable de test
se destruye, y esa variable contiene la única copia de un puntero a un duplicado de la cadena "etc"
.
A veces en los programas C, a veces no nos importan las fugas de este segundo tipo: memoria que no se libera cuando el programa finaliza, pero que no se asigna una y otra vez en un bucle (por lo que no causa un problema de crecimiento de memoria fuera de control) )
Si el programa se integra alguna vez en otro programa (por ejemplo, como una biblioteca compartida) donde la función main
original se convierte en una función de inicio que podría invocarse repetidamente en el mismo entorno de programa, ambas fugas se convertirán en problemas.
La función strdup
POSIX se comporta de manera similar a esto:
char *strdup(const char *orig)
{
size_t bytes = strlen(orig) + 1;
char *copy = malloc(bytes);
if (copy != 0)
memcpy(copy, orig, bytes);
return copy;
}
Sí; asigna nuevo almacenamiento cada vez.
Si tiene un recolector de basura (como Boehm) en su imagen C, entonces es posible que el almacenamiento que se filtró sea reciclado, por lo que strdup
puede reutilizar la misma memoria para la segunda asignación. (Sin embargo, un recolector de basura no va a entrar después de una sola asignación, a menos que se opere en un modo de prueba de estrés para eliminar errores).
Ahora, si realmente quiere reutilizar la memoria con realloc, puede cambiar su función x
en esta línea:
#include <stdlib.h>
#include <string.h>
void *strealloc(char *origptr, char *strdata)
{
size_t nbytes = strlen(strdata) + 1;
char *newptr = (char *) realloc(origptr, nbytes); /* cast needed for C++ */
if (newptr)
memcpy(newptr, strdata, nbytes);
return newptr;
}
(Por cierto, los nombres externos que comienzan con str
están en un espacio de nombres reservado de ISO C, pero strealloc
es un nombre demasiado bueno para rechazar).
Tenga en cuenta que la interfaz es diferente. No pasamos un puntero a puntero, sino que presentamos una interfaz similar a realloc
. La persona que llama puede verificar el valor de retorno de nulo para detectar un error de asignación, sin tener el puntero sobrescrito inconvenientemente con nulo en ese caso.
La función main
ahora se ve así:
int main(void)
{
char *test = strealloc(NULL, "abcd");
test = strealloc(test, "etc");
free(test);
return 0;
}
Al igual que antes, no hay verificación de errores. Si el primer strealloc
, la test
es entonces nula. Eso no ocurre ya que se sobrescribe de todos modos, y el primer argumento de strealloc
puede ser nulo.
Solo se necesita uno free
para tapar la fuga de memoria.