4 - Representación de una pila con arrays

Pila basada en memoria contigua

Cuando conocemos el tamaño máximo de una pila (o podemos estimarlo con confianza) la alternativa más sencilla es representarla mediante un array y una variable que actúe como tope. Esta configuración elimina llamadas a malloc, se beneficia de la localidad de caché y facilita el razonamiento en plataformas embebidas.

4.1 Estructura necesaria (stack struct)

La pila se encapsula en un struct que agrupa el buffer y los metadatos. Se pueden usar #define o constantes para centralizar la capacidad:

#include <stdio.h>

#define STACK_MAX 64

typedef struct {
  int datos[STACK_MAX];
  int top;
} Stack;

En implementaciones más genéricas se podría parametrizar el tipo de dato o envolverlo dentro de un typedef para reutilizarlo con diferentes tipos primitivos.

4.2 Capacidad máxima

La constante STACK_MAX fija el límite absoluto de elementos. Debe elegirse en función de la memoria disponible y del peor caso esperado. Conviene explicitar este valor en la interfaz pública para que los consumidores de la pila conozcan las restricciones.

Si se requiere modificarlo en tiempo de ejecución se puede migrar a un array dinámico, pero la versión estática demuestra la idea principal sin complejidad adicional.

4.3 Variable top

La variable top (o tope) representa el índice de la siguiente posición libre. Inicia en cero y se incrementa tras cada push. Para realizar un pop se decrementa y se lee el último valor insertado.

Ventaja clave: todas las operaciones dependen de incrementar o decrementar un entero, lo que garantiza tiempo O(1).

4.4 Inicialización

El procedimiento habitual consiste en establecer top = 0 y, opcionalmente, limpiar el array si se requieren valores conocidos. Ejemplo:

void stack_init(Stack *s) {
  s->top = 0;
}

int stack_is_empty(const Stack *s) {
  return s->top == 0;
}

Marca el estado inicial para evitar que el tope contenga basura de memoria y facilita escribir funciones auxiliares autoverificables.

4.5 Manejo de overflow y underflow

Dos condiciones críticas deben controlarse:

  • Overflow: ocurre cuando un push intenta sobrepasar STACK_MAX. La función debe rechazar la operación o reportar un error.
  • Underflow: aparece al ejecutar pop sobre una pila vacía. Se puede devolver un código de error, lanzar una asercion o retornar un valor centinela.
int stack_push(Stack *s, int valor) {
  if (s->top == STACK_MAX) {
    return 0; /* overflow */
  }
  s->datos[s->top++] = valor;
  return 1;
}

int stack_pop(Stack *s, int *out) {
  if (stack_is_empty(s)) {
    return 0; /* underflow */
  }
  *out = s->datos[--s->top];
  return 1;
}

El control explícito de estas condiciones evita lecturas fuera de rango y otorga mensajes claros a los consumidores del TDA. En sistemas críticos podría complementarse con registros de log o excepciones personalizadas si la plataforma lo soporta.

4.6 Código completo listo para CLion

Para compilar y probar el comportamiento en CLion basta con incluir una función main que ejecute algunas operaciones de prueba:

#include <stdio.h>

#define STACK_MAX 64

typedef struct {
  int datos[STACK_MAX];
  int top;
} Stack;

void stack_init(Stack *s) {
  s->top = 0;
}

int stack_is_empty(const Stack *s) {
  return s->top == 0;
}

int stack_push(Stack *s, int valor) {
  if (s->top == STACK_MAX) return 0;
  s->datos[s->top++] = valor;
  return 1;
}

int stack_pop(Stack *s, int *out) {
  if (stack_is_empty(s)) return 0;
  *out = s->datos[--s->top];
  return 1;
}

int main(void) {
  Stack pila;
  stack_init(&pila);

  stack_push(&pila, 10);
  stack_push(&pila, 20);
  stack_push(&pila, 30);

  int valor;
  while (stack_pop(&pila, &valor)) {
    printf("Pop: %d\n", valor);
  }

  return 0;
}

Justo con este snippet, CLion podrá compilar un ejecutable de consola y observar los mensajes Pop para validar el flujo LIFO.

Salida de consola mostrando operaciones pop
Resultado esperado del programa de ejemplo en CLion.