En este programa (C, no C++) , ¿por qué malloc siempre devuelve el tamaño correcto independientemente del uso del operador sizeof?
#include <stdio.h> #include <stdlib.h> int main(void) { char *c = malloc(3); short *s = malloc(3); /* or malloc(3 * sizeof(short))? */ int *i = malloc(3); /* or malloc(3 * sizeof(int))? */ long *l = malloc(3); /* or malloc(3 * sizeof(long))? */ printf("%p\n", c++); printf("%p\n", c++); printf("%p\n", c++); printf("---\n"); printf("%p\n", s++); printf("%p\n", s++); printf("%p\n", s++); printf("---\n"); printf("%p\n", i++); printf("%p\n", i++); printf("%p\n", i++); printf("---\n"); printf("%p\n", l++); printf("%p\n", l++); printf("%p\n", l++); return 0; }La salida es:
0x1e82010 (1 byte) 0x1e82011 0x1e82012 --- 0x1e82030 (2 bytes) 0x1e82032 0x1e82034 --- 0x1e82050 (4 bytes) 0x1e82054 0x1e82058 --- 0x1e82070 (8 bytes) 0x1e82078 0x1e82080¿Me estoy perdiendo de algo?
4.0.4-303.fc22.x86_64 clang versión 3.5.0 (tags/RELEASE_350/final) Destino: x86_64-redhat-linux-gnu Modelo de hilo: posix
long *l = malloc(3);Esto asigna (o más bien intenta asignar) 3 bytes .
Por lo general malloc() en realidad asignará más de lo que solicita, con fines de alineación y contabilidad. Entonces, después de llamar a malloc(3) , es posible que pueda salirse con la suya almacenando 3 valores long en la memoria asignada. Pero no está garantizado.
Sí, necesitas el sizeof de .
Y la mejor manera de escribir eso es:
long *l = malloc(3 * sizeof *l); Al usar el tamaño de lo que apunta el puntero ( sizeof *l ), no tiene que especificar el tipo long dos veces, y el código no se romperá si el tipo cambia más adelante.
Aun mejor:
long *l = malloc(3 * sizeof *l); if (l == NULL) { /* malloc failed, recover or bail out */ }Si lo prefiere, puede escribir esto como:
long *l = malloc(3 * sizeof(*l)); pero los paréntesis adicionales no son necesarios, size sizeof es un operador unario, no una función.
printf("%p\n", l++); printf("%p\n", l++); printf("%p\n", l++); Incrementar un puntero lo hace avanzar según el tamaño del tipo al que apunta. Aparentemente, long es de 8 bytes en su sistema, por lo que esto avanzará l por lo menos 24 bytes, mucho más allá de los 3 bytes que solicitó de malloc . El resultado es un comportamiento indefinido.
Y al incrementar l , ha perdido el valor original devuelto por malloc ; lo necesitará cuando sea el momento de llamar a free() .
Finalmente, el especificador de formato %p requiere un argumento de tipo void* . Es probable que pasar un tipo de puntero diferente "funcione", pero realmente debería convertirlo en void* :
printf("%p\n", (void*)l++);¿Me estoy perdiendo de algo?
Sí, te estás perdiendo totalmente el punto.
Está probando la aritmética de punteros , que se define en términos del tamaño del tipo apuntado. Eso no tiene absolutamente nada que ver con la cantidad de memoria asignada por malloc() , o incluso si el puntero en cuestión apunta a una dirección válida.
Incrementar un puntero incrementa la dirección almacenada por el tamaño del tipo base. No depende de a qué apunta el puntero.