Variables de stack vs. Variables de stack

Estoy en lo cierto al pensar que:

char *buff[500]; 

… crea una variable de stack, y:

 char *buff = (char *)malloc(500); 

… crea una variable de montón?

Si eso es correcto, cuándo y por qué usarías las variables de stack sobre las variables de stack y viceversa. Entiendo que la stack es más rápida, ¿hay algo más?

Una última pregunta, ¿la función principal es un marco de stack en la stack?

Sí, primero se crea una matriz de punteros de caracteres en la stack, aproximadamente 500*4 bytes y el segundo asigna 500 caracteres en el montón y se apunta a ellos por una stack.

Asignar en la stack es fácil y rápido, pero la stack es limitada, el montón es más lento pero mucho más grande. Además de eso, los valores asignados de stack se “borran” una vez que se abandona el scope, por lo que es muy bueno para valores locales pequeños como variables primitivas.

Si asigna demasiado en la stack, puede quedarse sin stack y morir, main ya que todas las funciones que ejecuta tienen un marco de stack en la stack y todas las variables locales de la función se almacenan allí, por lo que profundizan en la función de llamadas también puede llevarte a un stackoverflow.

En general, es una buena regla general para asignar todo lo que usa a menudo y es más grande que cien bytes en el montón, y pequeñas variables y punteros en la stack.

Al ver que escribiste

 char *buff = (char *)malloc(500); 

usted probablemente quiso decir

 char buff[500]; instead of char* buff[500]; 

en su primer ejemplo (para que tenga una matriz char, no una matriz de punteros a caracteres)

Sí, la “asignación” en la stack es más rápida porque solo aumenta un puntero almacenado en el registro ESP.

Necesitas variables de montón si quieres:

1) más memoria que la que cabe en la stack (generalmente mucho antes)

2) pasar la memoria asignada por una función llamada a la función de llamada.

Tus buff no son equivalentes.

El primero ( char *buff[500] ) es una matriz de 500 punteros; el 2º ( char *buff = (char *)malloc(500) ) es un puntero.

El puntero ( en la stack ) apunta a 500 bytes de memoria (si la llamada malloc tuvo éxito) en el montón.
La matriz de punteros está en la stack. Sus punteros no están inicializados.

A menos que use C99, al usar la stack, el tamaño de la matriz debe conocerse en tiempo de comstackción. Eso significa que no puedes hacer:

 int size = 3; // somewhere, possibly from user input char *buff[size]; 

Pero al usar “el montón” (asignación dinámica), puede proporcionar las dimensiones que desee. Esto se debe a que la asignación de memoria se realiza en tiempo de ejecución, en lugar de estar codificada en el ejecutable.

Las variables de Heap se pueden crear dinámicamente, es decir, puede pedirle un tamaño a su usuario y malloc una nueva variable con este tamaño.

El tamaño de una variable de stack debe conocerse en tiempo de comstackción.

Como dijiste, la variable de stack se asigna y se accede más rápidamente. Así que les recomendaré usarlos cada vez que conozcan el tamaño en el momento de la comstackción. De lo contrario, no tiene elección, debe usar malloc()

Esta es de hecho una variable asignada en la stack:

 char buff[500]; // You had a typo here? 

y esto está en el montón:

 char *buff = (char *)malloc(500); 

¿Por qué usarías uno frente al otro?

  • En char *buff[500] , el 500 necesita ser una constante en tiempo de comstackción. No puede usarlo si 500 se calcula en tiempo de ejecución.
  • Por otro lado, las asignaciones de stack son instantáneas, mientras que las asignaciones de montón toman tiempo (por lo tanto, incurren en un costo de rendimiento en tiempo de ejecución).
  • El espacio en la stack está limitado por el tamaño de stack del subproceso (normalmente 1 MB antes de que se produzca un desbordamiento de stack), mientras que hay mucho más disponible en el montón.
  • Si asigna una matriz en la stack lo suficientemente grande como para ocupar más de 2 páginas de memoria virtual gestionada por el sistema operativo, y accede al final de la matriz antes de hacer cualquier otra cosa, existe la posibilidad de obtener un error de protección (esto depende de el SO)

Finalmente: cada función llamada tiene un marco en la stack. La función main no es diferente. Ni siquiera es más especial que las otras funciones de su progtwig, ya que cuando el progtwig comienza a ejecutarse, el primer código que se ejecuta se encuentra dentro the C runtime environment Después de que el tiempo de ejecución esté listo para comenzar la ejecución de su propio código, llama a main como llamaría a cualquier otra función.

El estándar C no contiene ni las palabras montón ni stack . Lo que tenemos aquí en cambio son dos duraciones de almacenamiento (de 4 en total): automáticas y asignadas :

  •  char buff[500]; // note the missing * to match the malloc example 

    dentro de una función declara el buff objeto como una matriz de char y tiene una duración de almacenamiento automática . El objeto dejará de estar cuando se salga del bloque donde se declaró el objeto.

  •  char *buff = malloc(500); // no cast necessary; this is C 

    declarará buff como un puntero a char . malloc reservará 500 bytes continuos y le devolverá un puntero. El objeto devuelto de 500 bytes existirá hasta que esté explícitamente free d con una llamada a free . Se dice que el objeto ha asignado la duración de almacenamiento .


Eso es todo lo que el estándar C dice. No especifica que el ” char buff[500] necesita ser asignado desde una “stack”, o que debe haber una stack. No especifica que el malloc necesita usar algún “montón”. Por el contrario, un comstackdor podría implementar internamente el char buff[500] como

 { char *buff = malloc(500); free(buff); } 

O puede deducir que la memoria asignada no se usa, o que solo se usa una vez, y usa una asignación basada en stack en lugar de llamar realmente malloc .

En la práctica, la mayoría de los comstackdores y entornos actuales usarán un diseño de memoria denominado stack para variables automáticas, y los objetos con duración de almacenamiento asignada provienen del “montón” que es una metáfora del desorden no organizado que se compara con la stack ordenada , pero no es algo que tiene que ser así.

Esos dos no son equivalentes. El primero es una matriz de tamaño 500 (en la stack) con punteros a los personajes. El segundo es un puntero a un fragmento de memoria de 500 que se puede usar con el operador de indexación.

 char buff[500]; char *buff = (char *)malloc(sizeof(char)*500); 

Las variables de stack deben preferirse porque no requieren desasignación. Las variables de stack permiten el paso de datos entre ámbitos y la asignación dinámica.