ejemplos - Uso adecuado de realloc()
memoria dinamica en c (6)
Aplicar correcciones como ediciones, basadas en los buenos comentarios a continuación.
Leyendo esta pregunta comp.lang.c , revela 3 casos:
- "Cuando puede, simplemente te devuelve el mismo puntero que le diste".
- "Pero si debe ir a otra parte de la memoria para encontrar suficiente espacio contiguo, devolverá un puntero diferente (y el valor del puntero anterior se volverá inutilizable)".
- "Si
realloc
no puede encontrar suficiente espacio, devuelve un puntero nulo y deja asignada la región anterior".
Esto se puede traducir directamente al código:
int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
// Case 3, clean up then terminate.
free(ptr);
exit(0);
}
else if(tmp == ptr)
{
// Case 1: They point to the same place, so technically we can get away with
// doing nothing.
// Just to be safe, I''ll assign NULL to tmp to avoid a dangling pointer.
tmp = NULL;
}
else
{
// Case 2: Now tmp is a different chunk of memory.
ptr = tmp;
tmp = NULL;
}
Entonces, si lo piensas bien, el código que publicaste está bien (casi). El código anterior se simplifica a:
int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
// Case 3.
free(ptr);
exit(0);
}
else if(ptr != tmp)
{
ptr = tmp;
}
// Eliminate dangling pointer.
tmp = NULL;
Tenga en cuenta el extra else if(ptr != tmp)
, que excluye el Caso 1, donde no querría llamar free(ptr)
porque ptr
y tmp
refieren a la misma ubicación. Además, solo por razones de seguridad, me aseguro de asignar NULL
a tmp
para evitar cualquier problema de puntero mientras el tmp
está dentro del alcance.
De man realloc: La función realloc () devuelve un puntero a la memoria recién asignada, que está adecuadamente alineada para cualquier tipo de variable y puede ser diferente de ptr, o NULL si la solicitud falla.
Así que en este fragmento de código:
ptr = (int *) malloc(sizeof(int));
ptr1 = (int *) realloc(ptr, count * sizeof(int));
if(ptr1 == NULL){ //reallocated pointer ptr1
printf("Exiting!!/n");
free(ptr);
exit(0);
}else{
free(ptr); //to deallocate the previous memory block pointed by ptr so as not to leave orphaned blocks of memory when ptr=ptr1 executes and ptr moves on to another block
ptr = ptr1; //deallocation using free has been done assuming that ptr and ptr1 do not point to the same address
}
¿Es suficiente simplemente suponer que el puntero reasignado apunta a un bloque diferente de memoria y no al mismo bloque? Porque si la suposición se vuelve falsa y realloc devuelve la dirección del bloque de memoria original apuntado por ptr y luego free (ptr) se ejecuta (por el motivo dado en los comentarios) luego el bloque de memoria se borrará y el programa se volvería loco. ¿Debo poner otra condición que compare la igualdad de ptr y ptr1 y excluya la ejecución de la declaración libre (ptr)?
No debe free
su puntero original si el realloc
tiene éxito. Si free
ese puntero si el realloc
falla, depende de las necesidades de su aplicación particular; Si no puede continuar sin esa memoria adicional, esto sería un error fatal y podría desasignar cualquier almacenamiento retenido y salir. Si, OTOH, aún puede continuar (tal vez ejecute una operación diferente y espere que la memoria esté disponible más adelante), es probable que desee conservar esa memoria y luego intentar otra realloc
.
7.22.3.5 La función realloc
Sinopsis
1
#include <stdlib.h> void *realloc(void *ptr, size_t size);
Descripción
2 La función
realloc
desasigna el objeto antiguo al que apuntaptr
y devuelve un puntero a un nuevo objeto que tiene el tamaño especificado porsize
. El contenido del nuevo objeto debe ser el mismo que el anterior antes de la desasignación, hasta el menor de los nuevos y antiguos tamaños. Todos los bytes en el nuevo objeto más allá del tamaño del objeto antiguo tienen valores indeterminados.3 Si
ptr
es un puntero nulo, la funciónrealloc
comporta como la funciónmalloc
para el tamaño especificado. De lo contrario, siptr
no coincide con un puntero devuelto por una función de administración de memoria, o si el espacio ha sido desasignado por una llamada a la funciónfree
orealloc
, el comportamiento no se define. Si no se puede asignar memoria para el nuevo objeto, el objeto anterior no se desasigna y su valor no cambia.Devoluciones
4 La función
realloc
devuelve un puntero al nuevo objeto (que puede tener el mismo valor que un puntero al objeto anterior), o un puntero nulo si no se pudo asignar el nuevo objeto.
Énfasis añadido. Nota cláusula 4; el puntero devuelto puede ser el mismo que el puntero original.
OP: ... puede ser diferente de ptr, o NULL si la solicitud falla.
A: No siempre. NULL
puede ser devuelto legítimamente (no un error), si el count
es 0.
OP: ¿Es suficiente suponer que el puntero reasignado apunta a un bloque de memoria diferente y no al mismo bloque?
A: No
OP: ¿Debo poner otra condición que compare la igualdad de ptr y ptr1 y excluya la ejecución de la declaración libre (ptr)?
A: No.
Si realloc()
devuelve NULL
(y el conteo no es 0), el valor de ptr
sigue siendo válido, apuntando a los datos sin cambiar de tamaño. free(ptr)
o no depende de tus metas.
Si realloc()
no devuelve NULL
, no free(ptr)
, todo está listo liberado.
Ejemplo: https://codereview.stackexchange.com/questions/36662/critique-of-realloc-wrapper
#include <assert.h>
#include <stdlib.h>
int ReallocAndTest(char **Buf, size_t NewSize) {
assert(Buf);
void *NewBuf = realloc(*Buf, NewSize);
if ((NewBuf == NULL) && (NewSize > 0)) {
return 1; // return failure
}
*Buf = NewBuf;
return 0;
}
Si realloc
mueve sus datos, liberará el antiguo puntero para usted entre bastidores. No tengo una copia del estándar C11, pero está garantizado en el estándar C99.
Simplemente no llame a free()
en su ptr original en el camino feliz. Esencialmente realloc()
ha hecho eso por ti.
ptr = malloc(sizeof(int));
ptr1 = realloc(ptr, count * sizeof(int));
if (ptr1 == NULL) // reallocated pointer ptr1
{
printf("/nExiting!!");
free(ptr);
exit(0);
}
else
{
ptr = ptr1; // the reallocation succeeded, we can overwrite our original pointer now
}
realloc
devolverá la misma dirección a ptr
si tiene suficiente espacio para extender la porción real de memoria apuntada por ptr
. De lo contrario, moverá los datos a la nueva parte y liberará la parte antigua. No se puede confiar en que ptr1
sea diferente a ptr
. Su programa se comporta indefinido.
Si realloc
devuelve otra dirección, primero desasigna la anterior para que no tenga que hacerlo usted mismo.
Por cierto, nunca lances el retorno de malloc/realloc
:). Tu código debería ser así:
ptr=malloc(sizeof(int));
ptr=realloc(ptr,count*sizeof(int));
if(ptr==NULL)
{
// error!
printf("/nExiting!!");
// no need to free, the process is exiting :)
exit(0);
}