Si existe un aspecto que genera como norma general confusión entre quienes se están iniciando en C, ese es el relativo a la asignación de memoria en el Stack y el Heap. La respuesta reside en la comprensión de como el código es ejecutado en el nivel mas bajo.

 

STACK

Cuando un programa es ejecutado, a cada hilo se le asigna una cantidad limitada de espacio en el Stack. El Stack almacena la información usada por el programa incluyendo el byte-code ejecutado por el procesador. Se trata de un fragmento de memoria donde se van apilando linealmente (estructura LIFO) las distintas funciones ejecutadas así como las variables locales de cada una de ellas. El modo en como se asignara la memoria en el Stack, se define durante el proceso de compilado.
Algunas consideraciones y aspectos sobre el Stack:

  • Las variables almacenadas en el Stack (o variables automáticas) son almacenadas directamente a esta memoria.
  • Su acceso es muy rápido.
  • Es liberada al terminar la ejecución.
  • Fragmentos grandes de memoria, como arrays  de gran envergadura, no deberían ser almacenados en el Stack, para prevenir desbordamientos del mismo (Stack Overflow).
  • Las variables almacenadas en el Stack solamente son accesibles desde el bloque de código donde fueron declaradas.

En el siguiente código , x es almacenada en el Stack. Su valor no es accesible desde fuera del bloque if(), de modo que intentar acceder a esa variable fuera del bloque, generaria en un error de compilación.
Ejemplo de asignación de memoria en el Stack:

1
2
3
4
5
6
void main(){
if(true) {
int x = 0;
}
x = 1;
}

 

HEAP

El Heap a diferencia del Stack, no posee ninguna estructura de asignación de espacios (a diferencia del modelo LIFO en el Stack), y su tamaño se ve únicamente limitado por el tamaño de la memoria virtual (RAM y espacio SWAP). Es asignada al vuelo, durante la ejecución del programa (mediante malloc() por ejemplo), sin garantía de que los bloques otorgados sean contiguos.

  • La manipulación del  Heap (asignacion, lectura, escritura) es mas lenta que la del Stack .
  • Esta memoria se mantiene en uso hasta que se libera explicitamente por el programa. (o es liberada por el SO al terminar la ejecución del mismo)
  • Puede ser accedida desde fuera del bloque donde fue asignada.

En el siguiente código, la memoria para la variable x es asignada cuando main() es ejecutado, y permanece en memoria hasta que se llama a liberar() . Ademas como se aprecia, el valor de x es asignado fuera del bloque if() donde el espacio de memoria es asignado.
Ejemplo de asignación de memoria en el Heap:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void liberar();
int *x;

void main(){
if(true) {
x = malloc(sizeof(int));
}
*x = 1;
liberar();
}

void liberar(){
free(x);
}

 

CONCLUSIONES

En resumen, las variables temporales deben ser almacenadas en el stack. Resulta mas cómodo, y rápido pues no hay que preocuparse por la asignación de la memoria, el código resulta mas fácil de leer, y el acceso a las variables mas ágil puesto que el programa no tiene que asignar memoria al vuelo.
Para variables de gran tamaño, variables cuyo tamaño es dinámico  o variables globales, es conveniente usar el Heap. Una practica indispensable al usar asignación de memoria en el Heap, es la de liberarla memoria una vez terminemos de necesitarla.

BONUS

Para una visión mas clara sobre el funcionamiento del Stack y del Heap, asi como su manipulación, acompaño el siguiente vídeo (ENG) al artículo, donde además de comentar los puntos ya expuestos, se profundiza de forma bastante didáctica en el tema.