resueltos que perfectos matriz lineales lineal hamming generadora ejercicios códigos codigos codigo ciclicos bloque c memory free malloc

que - Si free() conoce la longitud de mi matriz, ¿por qué no puedo solicitarla en mi propio código?



matriz generadora g (9)

Además del punto correcto de Klatchko de que el estándar no lo proporciona, las implementaciones reales malloc / free a menudo asignan más espacio de lo que usted solicita. Por ejemplo, si solicita 12 bytes, puede proporcionar 16 (consulte A Allocator Memory , que señala que 16 es un tamaño común). Por lo tanto, no necesita saber que pidió 12 bytes, solo que le dio un fragmento de 16 bytes.

Sé que es una convención común pasar la longitud de las matrices asignadas dinámicamente a las funciones que las manipulan:

void initializeAndFree(int* anArray, size_t length); int main(){ size_t arrayLength = 0; scanf("%d", &arrayLength); int* myArray = (int*)malloc(sizeof(int)*arrayLength); initializeAndFree(myArray, arrayLength); } void initializeAndFree(int* anArray, size_t length){ int i = 0; for (i = 0; i < length; i++) { anArray[i] = 0; } free(anArray); }

pero si no hay forma de que obtenga la longitud de la memoria asignada desde un puntero, ¿cómo sabe free() automágicamente free() lo que debe desasignar cuando todo lo que le doy es el mismo puntero? ¿Por qué no puedo entrar en la magia, como programador de C?

¿De dónde obtiene free () su conocimiento gratuito (har-har)?


Después de leer la respuesta de Klatchko , yo mismo lo intenté y ptr[-1] hecho almacena la memoria real (generalmente más que la memoria que pedimos probablemente para guardar contra la falla de segmentación).

{ char *a = malloc(1); printf("%u/n", ((size_t *)a)[-1]); //prints 17 free(a); exit(0); }

Probando con diferentes tamaños, GCC asigna la memoria de la siguiente manera:

Inicialmente, la memoria asignada es de 17 bytes.
La memoria asignada es por lo menos 5 bytes más que el tamaño solicitado, si se solicita más, asigna 8 bytes más.

  • Si el tamaño es [0,12], la memoria asignada es 17.
  • Si el tamaño es [13], la memoria asignada es 25.
  • Si el tamaño es [20], la memoria asignada es 25.
  • Si el tamaño es [21], la memoria asignada es 33.

No puede obtenerlo porque el comité C no lo exigió en el estándar.

Si está dispuesto a escribir algún código no portátil, puede tener suerte con:

*((size_t *)ptr - 1)

o tal vez:

*((size_t *)ptr - 2)

Pero si eso funciona dependerá exactamente de dónde la implementación de malloc que está utilizando almacena esos datos.


Para responder a la pregunta sobre eliminar [], las primeras versiones de C ++ en realidad requerían que llamaras a delete [n] y le dijeras el tamaño del tiempo de ejecución, para que no tuviera que almacenarlo. Lamentablemente, este comportamiento se eliminó como "demasiado confuso".

(Ver D y E para más detalles).


Puede asignar más memoria al tamaño de la tienda:

void my_malloc(size_t n,size_t size ) { void *p = malloc( (n * size) + sizeof(size_t) ); if( p == NULL ) return NULL; *( (size_t*)p) = n; return (char*)p + sizeof(size_t); } void my_free(void *p) { free( (char*)p - sizeof(size_t) ); } void my_realloc(void *oldp,size_t new_size) { ... } int main(void) { char *p = my_malloc( 20, 1 ); printf("%lu/n",(long int) ((size_t*)p)[-1] ); return 0; }


Sé que este hilo es un poco viejo, pero aún tengo algo que decir. Hay una función (o una macro, todavía no he comprobado la biblioteca) malloc_usable_size () - obtiene el tamaño del bloque de memoria asignado desde el montón. La página man indica que es solo para la depuración, ya que genera no el número que ha pedido, sino el número que ha asignado, que es un poco más grande. Observe que es una extensión de GNU.

Por otro lado, puede que ni siquiera sea necesario, porque creo que para liberar el trozo de memoria no tienes que saber su tamaño. Simplemente elimine el mango / descriptor / estructura que está a cargo del trozo.


Si bien es posible obtener los metadatos que el asignador de memoria coloca antes del bloque asignado, esto solo funcionaría si el puntero es realmente un puntero a un bloque asignado dinámicamente. Esto afectaría seriamente la utilidad de la función, requiriendo que todos los argumentos pasados ​​fueran punteros a dichos bloques, en lugar de decir una simple matriz automática o estática.

El punto es que no hay manera portátil de inspeccionar el puntero para saber a qué tipo de memoria apunta. Entonces, si bien es una idea interesante, no es una propuesta particularmente segura.

Un método que es seguro y portátil sería reservar la primera palabra de la asignación para mantener la longitud. GCC (y tal vez algunos otros compiladores) admite un método no portátil de implementación utilizando una estructura con una matriz de longitud cero que simplifica el código en cierta medida en comparación con una solución portátil:

typedef tSizedAlloc { size_t length ; char* alloc[0] ; // Compiler specific extension!!! } ; // Allocating a sized block tSizedAlloc* blk = malloc( sizeof(tSizedAlloc) + length ) ; blk->length = length ; // Accessing the size and data information of the block size_t blk_length = blk->length ; char* data = blk->alloc ;


Una forma no estándar es usar _msize() . El uso de esta función hará que su código sea poco práctico. Además, la documentación no es muy clara en cuanto a que devolverá el número pasado a malloc() o el tamaño real del bloque (podría ser mayor).


malloc implementador de malloc cómo almacenar esta información. La mayoría de las veces, la longitud se almacena directamente en frente de la memoria asignada (es decir, si desea asignar 7 bytes, se asignan 7 + x bytes en realidad, donde se utilizan los x bytes adicionales para almacenar los metadatos). A veces, los metadatos se almacenan antes y después de la memoria asignada para verificar la corrupción del montón. Pero el implementador también puede elegir usar una estructura de datos adicional para almacenar los metadatos.