2010-12-09 26 views
13

Esta pregunta se hizo en la ronda por escrito de una entrevista de trabajo:de asignación de memoria Problema

#include<alloc.h> 
#define MAXROW 3 
#define MAXCOL 4 

main() 
    { 
    int (*p)[MAXCOL]; 
    p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p))); 
    } 

¿Cuántos bytes se asignan en el proceso?

Para ser sincero, no respondí la pregunta. No entendí la asignación a p.

¿Alguien me puede explicar cuál sería la respuesta y cómo se puede deducir?

+1

El que hizo esta pregunta de la entrevista, obviamente, nunca trató de compilar el código realidad. –

+0

¿Estás seguro? Parece que podría compilarse en algunos sistemas basura ... –

+0

No sin un ')' adicional –

Respuesta

8

Depende de la plataforma.

int (*p)[MAXCOL]; declara un puntero a una matriz de elementos MAXCOL enteros de ancho (MAXCOL por supuesto es 4 en este caso). Un elemento de este puntero es por lo tanto 4*sizeof(int) en la plataforma de destino.

La instrucción malloc asigna un búfer de memoria MAXROW multiplicado por el tamaño del tipo contenido en P. Por lo tanto, en total, se asignan los enteros MAXROW * MAXCOL. El número real de bytes dependerá de la plataforma objetivo.

Además, probablemente haya memoria adicional utilizada por el tiempo de ejecución de C (como bookeeping interno en malloc, así como los diversos bits de inicialización de proceso que se producen antes de llamar a main), que también depende completamente de la plataforma.

6

sizeof(*p) será MAXCOL*sizeof(int). Entonces, total MAXROW*MAXCOL*sizeof(int) cantidad de bytes están asignados.

7

p es un puntero a una matriz de MAXCOL elementos de tipo int, por lo sizeof *p (paréntesis eran redundantes) es el tamaño de una matriz tal, es decir, MAXCOL*sizeof(int).

La conversión en el valor de retorno de malloc es innecesaria, fea y considerada perjudicial. En este caso, oculta un error grave: debido al prototipo perdido, se supone malloc implícitamente que se devuelve int, que es incompatible con su tipo de devolución correcta (void *), lo que da como resultado un comportamiento indefinido.

+0

si agrega a su respuesta los bytes reales asignados esta será la mejor respuesta aún – SiegeX

+0

El argumento suena bien, pero resulta que no es lo que sucede. Instrumenté el código y encontré 144 bytes asignados. –

+2

@Chris: la implementación que usa más de lo esperado no invalida el cálculo de R. Solo se puede calcular cuánto asigna el programa 'malloc' - un límite inferior -' malloc' es perfectamente libre de redondearlo de la forma que quiera, basado en cubos de tamaño fijo o tamaños de página que usa internamente para acelerar su algoritmos.Además, el programa puede asignar heap desde otro código de inicialización: tenga cuidado de no incluir eso al comparar las expectativas re 'p' y' malloc' explícitamente solicitadas. –

3

int (*p)[MAXCOL] == int (*p)[4] == "puntero a la matriz 4 de int" (véase la nota a continuación)

sizeof(*p) sería entonces lo p puntos a, es decir 4 * sizeof(int). Que se multiplican por MaxRow y su respuesta final es:

12 * sizeof(int) 

Nota: Esto está en contraste con:

int *p[MAXCOL] == == int *p[4] "matriz 4 de puntero a int"
Los paréntesis hacen bastante diferencia!

6

Es posible que desee comprobar cdecl para ayudar a traducir declaraciones de C al inglés. En este caso, int (*p)[4]; se convierte en declare p as pointer to array 4 of int.

+1

+1 para cdecl ... –

+0

+1 porque utilicé 'cdecl' mientras componía mi respuesta. (Inicialmente pensé que la declaración era una matriz de punteros de función en lugar de enteros sin procesar) –

0

Qué tal cero bytes porque eso ni siquiera se compilará sin el alloc.h no estándar.Si no puede compilarlo, no puede ejecutarlo y, si no puede ejecutarlo, no puede asignar ningún tipo de memoria.

+0

@mu: Nada dice que 'alloc.h' no está en otro lugar accesible para el compilador simplemente porque es un encabezado no estándar. Ciertamente utilizo encabezados 'boost' todo el tiempo que no son estándar y mis programas compilan muy bien. Estoy seguro de que aquí hay muchas personas que usan encabezados POSIX que no están en el estándar y * también * funcionan bien. –

+0

@Billy: Y nada dice que no intentemos compilar esto en un sistema si 'int' tiene dos bytes tampoco. Tampoco se especifica que no haya un '-Dmalloc = printf' en la línea de comando. Pero ahora ambos estamos recogiendo liendres, a continuación discutiremos sobre cuántos ángeles pueden bailar en la punta de un alfiler. –

+0

@mu: no entiendo qué 'int' tiene dos bytes tiene que ver con lo que dije. Quejarse de un encabezado que falta no pertenece a una respuesta, incluso si fue comprobadamente cierto. –

5
#include<alloc.h> 
#define MAXROW 3 
#define MAXCOL 4 
main() { 
    int (*p)[MAXCOL]; 
    p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p)); 
} 

¿Cuántos bytes se asignan en el proceso?

p es un puntero, por lo que va a ocupar sizeof(int(*)[MAXCOL]) en la pila, lo que podría parecer desalentadora, pero es casi siempre el mismo que sizeof(void*), sizeof(int*) o cualquier otro puntero. Obviamente, los tamaños de puntero son los que le dan a las aplicaciones su clasificación como 16-, 32-, 64-etc. bits, y este puntero tendrá el tamaño correspondiente.

entonces p es señalado en algún memoria obtenida de malloc ...

malloc(MAXROW * sizeof(*p)) 

sizeof(*p) es el tamaño de la matriz int que p puntos a, a saber sizeof(int) * MAXCOL, por lo que tenemos

malloc(MAXROW * (sizeof(int) * MAXCOL)) 

solicitado desde el montón. Para propósitos ilustrativos, si asumimos el tamaño común de 32 bits int, estamos viendo 48 bytes. El uso real puede redondearse a lo que sea que se sientan las rutinas de pila (las rutinas de pila a menudo usan "cubos" de tamaño fijo para acelerar sus operaciones).

Para confirmar esta expectativa, simplemente sustituir una función de registro de malloc():

#include <stdio.h> 

#define MAXROW 3 
#define MAXCOL 4 

void* our_malloc(size_t n) 
{ 
    printf("malloc(%ld)\n", n); 
    return 0; 
} 

int main() 
{ 
    int (*p)[MAXCOL]; 
    p = (int (*)[MAXCOL]) our_malloc(MAXROW*(sizeof(*p))); 
} 

salida en mi máquina Linux:

malloc(48) 

El hecho de que puntero devuelto de malloc se convierte al tipo de p doesn' t afecta la cantidad de asignación de memoria realizada.

Como R observa agudamente, la falta de un prototipo malloc haría que el compilador puede esperar para volver mallocint en lugar de la realidad-devuelto void*. En la práctica, es probable que el tamaño más bajo de (int) bytes del puntero sobreviva a la conversión, y si sizeof (void *) pasó a ser igual a sizeof (int), o - aún más tenue - la memoria del montón pasa a comenzar en una dirección representable en un int a pesar de que el tamaño de los punteros es mayor (es decir, todos los bits truncados eran 0 de todos modos), la desreferencia posterior del puntero podría funcionar. Plug barato: C++ no se compilará a menos que se vea el prototipo.

Dicho esto, tal vez su alloc.h contiene un prototipo malloc ... No tengo una alloc.h, así que supongo que es no estándar.

Cualquier programa también asignará memoria para muchas otras cosas, como un marco de pila que proporciona algún contexto dentro del cual se puede llamar a main(). La cantidad de memoria para que varía con el compilador, la versión del compilador, sistema operativo, etc ..

3

Debe ser MaxRow * MAXCOL * sizeof (int) número de bytes

3

No me gusta este tipo de preguntas, porque creo que es mucho mejor como ingeniero de trabajo ejecutar el experimento que suponer que usted sabe lo que está haciendo, especialmente si hay motivos para sospechar, como que un programa no funciona como se espera o alguien que hace preguntas engañosas.

#include <stdlib.h> 
#include <stdio.h> 
#define MAXROW 3 
#define MAXCOL 4 

main() 
{ 
    int (*p)[MAXCOL]; 
    int bytes = MAXROW * (sizeof(*p)); 
    p = (int (*)[MAXCOL]) malloc(bytes); 
    printf("malloc called for %d bytes\n", bytes); 
} 

en un sistema Linux de 32 bits:

gcc test.c
./a.out
malloc llamada durante 48 bytes

(editado para eliminar accidente pegar de multiplicar por MaxRow dos veces, dando un tamaño erróneo de 144 bytes)

+0

Estoy sorprendido de que GCC no se haya quejado de que no sea 'int main()'. –

+1

El problema con este enfoque es que no distingue el resultado específico de la implementación que se obtiene en una plataforma particular de lo que el estándar de lenguaje requiere que hagan todas las implementaciones (12 * sizeof int). Y si se basa únicamente en una prueba empírica, sin razonar al respecto en términos de cuáles son los requisitos de idioma, es posible que no note que se ha multiplicado por MAXROW dos veces y terminó con la respuesta incorrecta. –

+0

Es mucho más fácil encontrar errores tipográficos en el código que suposiciones fallidas sobre cuáles son los estándares de lenguaje. Soy muy consciente de cuáles son los tamaños de los tipos de datos en mi sistema, y ​​básicamente lo señalé.Al principio no estaba seguro de si el tamaño de la base era el de un int o un puntero (ya que ambos son del mismo tamaño), por lo que momentáneamente cambié el tipo a un corto para ver qué sucedería. Los experimentos empíricos resultan ser una muy buena forma de probar supuestos. –

1

Ejecutando lo siguiente en codepad.org:

//#include<alloc.h> 
#define MAXROW 3 
#define MAXCOL 4 

int main() 
{ 
    int (*p)[MAXCOL]; 
    p = (int (*)[MAXCOL]) malloc(MAXROW*(sizeof(*p))); 

    int x = MAXROW*(sizeof(*p)); 
    printf("%d", x); 

    return 0; 
} 

imprime 48.

¿Por qué? Porque MAXROW es 3 y sizeof(*p) es 16, entonces obtenemos 3 * 16.

¿Por qué sizeof(*p) 16? Como MAXCOL es 4, entonces p es un puntero a una matriz de 4 ints. Cada int es 32 bits = 4 bytes. 4 entradas en la matriz * 4 bytes = 16.

¿Por qué sizeof(*p) no es 4? Porque es el tamaño de lo que p apunta, no el tamaño de p. Para ser del tamaño de p, tendría que ser sizeof(p), que sería 4, ya que p es un puntero.

pedante habría que agregar:

  1. Si la máquina es de 64 bits (por ejemplo) la respuesta sería 96.
  2. Como los estados pregunta "¿Cuántos bytes se asignan en el proceso?", Se necesita agregar los 4 bytes para el puntero p.
  3. malloc puede asignar más de lo que pide (pero no menos) por lo que la pregunta no puede ser respondida.
  4. En una línea similar a 2, podría argumentar que, como el proceso también está cargando dlls del sistema como el dll C runtime para ejecutar, también está asignando el espacio para esos. Entonces, podría argumentar a favor del espacio asignado por las DLL que están siendo inyectadas en el proceso por otros procesos (no del sistema), como los inyectados por Actual Window Manager y su tipo. Pero, ¿cuán pedantescos queremos obtener?

pero creo que la pregunta es realmente pidiendo 48, con la posibilidad de obtener créditos extra para explicar 96.

+0

Algunos compiladores hacen int 32 bits de ancho incluso en arquitecturas de 64 bits. – JeremyP

+0

Combine el código en un C64 y el int tendrá 8 bits de ancho. Pedadicamente hablando ... – ThatGirl