memoria ejemplos dinamicos dinamica arreglos c memory-leaks dynamic-memory-allocation realloc calloc

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:

  1. "Cuando puede, simplemente te devuelve el mismo puntero que le diste".
  2. "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)".
  3. "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 .

Capítulo y verso :

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 apunta ptr y devuelve un puntero a un nuevo objeto que tiene el tamaño especificado por size . 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ón realloc comporta como la función malloc para el tamaño especificado. De lo contrario, si ptr 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ón free o realloc , 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); }