Pregunta

Tengo este fragmento de código

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

int main(){
    void *a, *b;

    a = malloc(16);
    b = malloc(16);
    printf("\n   block size (for a): %p-%p : %li", b, a, b-a);

    a = malloc(1024);
    b = malloc(1024);
    printf("\n   block size (for a): %p-%p : %li", b, a, b-a);  
}

¿No debería esto imprimir el último tamaño de bloque asignado (16 o 1024)? En su lugar, imprime 24 y 1032, por lo que la cantidad de memoria asignada parece tener 8 bytes adicionales.

Mi problema es (antes de hacer este caso de prueba) que hago malloc() en una función (1024 bytes) y devuelvo el resultado asignado. Al verificar el tamaño del bloque en el retorno de la función, obtengo 516 bloques ... y no entiendo por qué. Supongo que esta podría ser la razón de la corrupción de la memoria que ocurre después de realizar un procesamiento en los búferes asignados :)

Editar: he visto ¿Cómo puedo obtener el tamaño de una matriz de un puntero en C? y parece preguntar lo mismo, perdón por volver a publicar.

He rehecho mi ejemplo a mi código más específico:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

short int * mallocStuff(long int number, short int base){
    short int *array;
    int size=1024;

    array=(short int*)calloc(1,size);
    //array=(short int*)malloc(size);

    return array;
}

int main(){
    short int **translatedArray;

    translatedArray=malloc(4*sizeof(short int));

    int i;
    for(i=0;i<4;i++){
        translatedArray[i]=mallocStuff(0,0);

        if(i>0)
            printf("\n   block size (for a): %p-%p : %i",
                translatedArray[i], translatedArray[i-1], translatedArray[i]-translatedArray[i-1]);
    }

    return 0;
}

Y la salida es

   block size (for a): 0x804a420-0x804a018 : 516
   block size (for a): 0x804a828-0x804a420 : 516
   block size (for a): 0x804ac30-0x804a828 : 516

De acuerdo con la publicación anterior que es más grande que 1024. ¿Me equivoco?

¿Fue útil?

Solución

Tienes un error. En lugar de:

translatedArray=malloc(4*sizeof(short int));

Deberías tener

translatedArray=malloc(4*sizeof(short int*));

Tenga en cuenta el puntero faltante en su código. Sospecho que de aquí proviene su comportamiento observado.


Observe también que 0x804a420 - 0x804a018 = 1032, no 516. La fórmula translatedArray[i] - translatedArray[i - 1] le da el número de elementos (entradas cortas, o más simplemente, cortos) entre las dos direcciones, no el número de bytes .

Otros consejos

Primero, Malloc no garantiza que dos llamadas malloc sucesivas devuelvan punteros sucesivos.

Segundo, dependiendo de su arquitectura específica, se aplican diferentes reglas de alineación; a veces puede pedir un solo byte, pero la arquitectura prefiere asignaciones en intervalos de 8 o 4 bytes.

Tercero, malloc necesita algo de sobrecarga para almacenar qué tan grande es el bloque asignado, etc.

¡No haga suposiciones sobre lo que está haciendo malloc más allá de lo que dice la documentación!

La función malloc siempre asigna un poco más de lo que solicita, para almacenar información de contabilidad. Después de todo, cuando llama a free() necesita saber qué tan grande es el bloque.

Además, generalmente short int las implementaciones redondearán el tamaño solicitado hasta el siguiente múltiplo de 8 o 16 o algún otro número de redondeo.

Actualización : la verdadera respuesta a su pregunta radica en su uso del tipo <=>. Al hacer aritmética de puntero (sustracción) entre punteros mecanografiados, C y C ++ devuelven la diferencia en el número de las cosas apuntadas. Como está apuntando a <=>, que tiene un tamaño de dos bytes, el valor devuelto es la mitad de lo que esperaba.

Por otro lado, <=> siempre asigna un número dado de bytes , sin importar a qué arroje el resultado después. Prueba esto:

    array=(short int*)malloc(sizeof(short int) * size);

No hay garantías de que dos llamadas de malloc devuelvan bloques exactamente agrupados; de hecho, no hay ninguna garantía sobre el resultado, excepto que si no es NULL, apuntará a un bloque tan grande como el anterior. solicitado.

Internamente, la mayoría de los mallocs contienen datos de trabajo para ayudarlos a administrar el montón. Por ejemplo, esos 8 bytes pueden contener dos punteros: uno que apunta al siguiente bloque y otro que apunta al bloque anterior. No sé cuáles son esos 8 bytes porque no mencionaste en qué sistema operativo estás ejecutando, pero es perfectamente normal que Malloc use algo de memoria para sí mismo detrás de escena.

Algunos asignadores (por ejemplo, en Windows) proporcionan una función de biblioteca para descubrir el tamaño de bloque dado un puntero, sin embargo, algunos no lo hacen, ya que es una característica bastante esotérica.

Lo que devuelve malloc depende de la implementación de malloc y de la arquitectura. Como ya han dicho otros, tiene garantizado que obtendrá AL MENOS la cantidad de memoria solicitada, o NULL. Esta es también la razón por la que a veces, puede escribir más allá del final de una matriz, y no obtener una falla de segmentación. Es porque realmente tienes acceso válido a esta memoria, simplemente no lo sabías.

malloc () generalmente se implementa dividiendo el montón disponible en fragmentos de varios tamaños. En su caso, malloc () devuelve 2 fragmentos de 1024 (o 16) bytes consecutivos. Malloc () utiliza el espacio de 8 bytes que menciona para obtener información de contabilidad.

Vea las notas implícitas de Doug Lea malloc () aquí para comprender lo que está sucediendo detrás de escena: http://g.oswego.edu/dl/html/malloc.html

malloc() tendrá su propia sobrecarga.

Sin mencionar que no hay garantía de que 2 asignaciones consecutivas estarán una al lado de la otra para empezar.

Si malloc devuelve algo que no sea nulo, entonces la memoria que se le ha asignado para su programa tiene el tamaño que pasó a <=>. Tomar la diferencia de puntero entre los valores de retorno de dos llamadas de diferencia a <=> podría tener cualquier valor y no tiene nada (muy poco) que ver con el tamaño de bloque del primer bloque asignado.

Encontré esto ... y compruebe el enlace a continuación para obtener más información.

Asignación

Se asigna un bloque del grupo libre convirtiendo primero los bytes solicitados en un índice en la matriz de cubetas, utilizando la siguiente ecuación:

needed = solicitado + 8

Si es necesario < = 16, entonces bucket = 0

Si es necesario > dieciséis, entonces bucket = (log (necesario) / log (2) redondeado al entero más cercano) - 3

El tamaño de cada bloque en la lista anclada por el depósito es tamaño de bloque = 2 depósito + 4. Si la lista en el depósito es nula, la memoria se asigna utilizando la subrutina sbrk para agregar bloques a la lista. Si el tamaño del bloque es inferior a una página, se asigna una página utilizando la subrutina sbrk, y el número de bloques al dividir el tamaño del bloque en el tamaño de la página se agrega a la lista. Si el tamaño del bloque es igual o mayor que una página, la memoria necesaria se asigna utilizando la subrutina sbrk, y se agrega un solo bloque a la lista libre para el depósito. Si la lista libre no está vacía, el bloque al comienzo de la lista se devuelve a la persona que llama. El siguiente bloque de la lista se convierte en el nuevo encabezado.

http://publib.boulder.ibm.com/infocenter/systems/index.jsp?topic=/com.ibm.aix.genprogc/doc/genprogc/sys_mem_alloc.htm

Antes de que el puntero tenga el tamaño de la siguiente matriz, que es un entero de 32/64 bits (no sé si está firmado o no)

¿entonces la cantidad de memoria asignada parece tener 8 bytes adicionales? malloc() la implementación en su sistema parece asignar bytes adicionales para mantener la información de metadatos como qué tan grande es la sección de montón, cuál es dirección de inicio, etc. info.

Aunque varía en diferentes plataformas. En mis sistemas X86, 17 asignar un mínimo de malloc(0) bytes, incluso si estoy solicitando <=>.

int main(void) {
    int *p = malloc(0);
    if(p == NULL) {
        /* error handling */
    }
    printf("%d\n",p[-1]);/ *it prints 17 bytes */
    /* some code */
    return 0;
}

malloc () puede asignar memoria contigua, pero cuando llama malloc () 2 veces y no puede esperar que la memoria asignada sea contigua restando dos variables de punteros ...

Sin embargo, la memoria asignada es memoria virtual que es parte de la implementación del kernel, la gestión de memoria (VFS) es específica. Es posible que no afecte la funcionalidad de la aplicación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top