Café y Código
⛏️ Analogía MinecraftEstructura de Datos Fija

Arreglos Fijos en C++: El Inventario de 9 Espacios

Aprende cómo funcionan los arreglos estáticos tradicionales en C++ construyendo el sistema de gestión de la barra de acceso rápido (Hotbar) de Minecraft. Comprenderás la diferencia crucial entre capacidad máxima y cantidad ocupada, el paso de parámetros por referencia con &, y cómo implementar operaciones de agregar, mostrar, modificar y eliminar elementos desplazando memoria manualmente.

1. Primera Versión: El Inventario de 9 Casillas

En Minecraft, la barra de acceso rápido del jugador tiene exactamente 9 casillas fijas numeradas internamente desde la posición 0 hasta la posición 8. Cada casilla almacena el nombre de un objeto en forma de texto (string).

🎮 Barra Rápida (Hotbar) de Minecraftstring inventario[9]
🗡️Espadaidx: 0
⛏️Picoidx: 1
🪓Hachaidx: 2
🍞Panidx: 3
🪵Maderaidx: 4
🪨Piedraidx: 5
💎Diamanteidx: 6
🕯️Antorchaidx: 7
🏹Arcoidx: 8
string inventario[9] = { "Espada", "Pico", "Hacha", "Pan", "Madera", "Piedra", "Diamante", "Antorcha", "Arco" };

Para recorrer y mostrar todos los elementos en consola utilizamos un bucle for que comienza en el índice 0 y avanza hasta 8 (es decir, mientras i < 9):

Inventario de 9 elementos en C++
CPP
1#include <iostream>
2#include <string>
3
4using namespace std;
5
6int main() {
7 // Declaración e inicialización del arreglo fijo de 9 elementos
8 string inventario[9] = {
9 "Espada",
10 "Pico",
11 "Hacha",
12 "Pan",
13 "Madera",
14 "Piedra",
15 "Diamante",
16 "Antorcha",
17 "Arco"
18 };
19
20 // Recorrer las 9 posiciones del inventario
21 for (int i = 0; i < 9; i++) {
22 cout << "Posicion " << i << ": " << inventario[i] << endl;
23 }
24
25 return 0;
26}

2. Modificar un Elemento por Posición

Para cambiar un objeto de la casilla usamos el operador de acceso por corchetes inventario[posicion]. Al conocer el índice exacto, C++ accede y modifica la memoria en tiempo constante $O(1)$:

Modificar casilla del inventario
CPP
1int posicion;
2cout << "Que posicion desea modificar (0-8): ";
3cin >> posicion;
4
5cout << "Nuevo objeto: ";
6cin >> inventario[posicion]; // Asignamos el nuevo valor en esa casilla

Ejemplo de ejecución en consola:

Que posicion desea modificar (0-8): 3
Nuevo objeto: Manzana

El inventario ahora queda: Espada | Pico | Hacha | Manzana | Madera | Piedra | Diamante | Antorcha | Arco.

3. El Concepto Central: Capacidad vs. Cantidad Actual

En un videojuego real, el jugador rara vez comienza con el inventario lleno. Supongamos que al iniciar la partida solo tiene 6 objetos.

⚠️ Las Dos Variables Tienen Responsabilidades Distintas

El arreglo por sí mismo no sabe cuántos elementos estamos usando conceptualmente. Por eso, siempre que trabajamos con arreglos fijos necesitamos dos datos complementarios:

Variable 1: El Arreglostring inventario[9];

Representa la CAPACIDAD MÁXIMA disponible (9 casillas físicas en memoria).

Variable 2: El Contadorint cantidadInventario = 6;

Representa la CANTIDAD ACTUAL de objetos almacenados (slots ocupados).

Estado del Inventario:

Capacidad máxima: 9 casillas

Cantidad ocupada: 6 objetos (índices 0 al 5)

Espacios libres: 3 casillas disponibles (índices 6, 7 y 8)

Gracias a cantidadInventario = 6, cuando queramos mostrar el inventario en pantalla, el bucle solo debe iterar hasta cantidadInventario:

Iterar según la cantidad ocupada
CPP
1// Correcto: iteramos solo sobre los objetos que realmente existen
2for (int i = 0; i < cantidadInventario; i++) {
3 cout << i << " - " << inventario[i] << endl;
4}

4. Funciones y Paso por Referencia con &

Para que nuestro código sea limpio y reutilizable, trasladamos la lógica a funciones independientes.

A. Función para Mostrar el Inventario

Esta función solo lee los datos sin modificar el contador de cantidad:

Función mostrarInventario
CPP
1void mostrarInventario(string inventario[], int cantidadInventario) {
2 if (cantidadInventario == 0) {
3 cout << "El inventario esta vacio." << endl;
4 return;
5 }
6
7 for (int i = 0; i < cantidadInventario; i++) {
8 cout << i << " - " << inventario[i] << endl;
9 }
10}

B. Función para Agregar: ¿Por qué int& cantidadInventario lleva &?

Cuando el jugador recoge un nuevo objeto (ej. "Diamante"), la siguiente casilla libre está en el índice cantidadInventario. Al guardarlo, debemos incrementar cantidadInventario++ para que el programa recuerde que ahora tiene 7 objetos.

🚨 Explicación de Memoria: ¿Qué pasa con y sin &?

❌ SIN '&' (Paso por Copia):

La función recibe una copia aislada de cantidadInventario. Dentro de la función la copia aumenta a 7, pero al salir de la función esa copia se destruye. En el main el valor sigue siendo 6. ¡El nuevo objeto se perderá en la siguiente inserción!

✅ CON '&' (Paso por Referencia):

El símbolo & le indica a C++ que trabaje directamente sobre la variable original del main. Cuando la función hace cantidadInventario++, modifica la memoria real de main, pasando de 6 a 7 permanentemente.

Función agregarObjeto con paso por referencia
CPP
1void agregarObjeto(string inventario[], int& cantidadInventario) {
2 // 1. Validar si alcanzamos la capacidad máxima
3 if (cantidadInventario >= 9) {
4 cout << "El inventario esta lleno (Capacidad maxima: 9)." << endl;
5 return;
6 }
7
8 string objeto;
9 cout << "Ingrese el nombre del objeto: ";
10 cin >> objeto;
11
12 // 2. Guardar en la primera posicion libre (indice = cantidadInventario)
13 inventario[cantidadInventario] = objeto;
14
15 // 3. Aumentar el contador real en main
16 cantidadInventario++;
17
18 cout << "¡" << objeto << " guardado en la casilla " << cantidadInventario - 1 << "!" << endl;
19}

5. Operaciones CRUD con Arreglos Fijos

Un sistema CRUD cubre las 4 operaciones esenciales: Create (Crear/Agregar), Read (Leer/Mostrar), Update (Actualizar/Modificar) y Delete (Eliminar).

Update: Modificar Objeto

Verificamos que la posición ingresada sea válida (entre 0 y cantidadInventario - 1) y sobrescribimos el valor.

Función modificarObjeto
CPP
1void modificarObjeto(string inventario[], int cantidadInventario) {
2 if (cantidadInventario == 0) {
3 cout << "No hay objetos para modificar." << endl;
4 return;
5 }
6
7 int posicion;
8 cout << "Posicion a modificar (0 a " << cantidadInventario - 1 << "): ";
9 cin >> posicion;
10
11 if (posicion < 0 || posicion >= cantidadInventario) {
12 cout << "Posicion invalida." << endl;
13 return;
14 }
15
16 cout << "Objeto actual: " << inventario[posicion] << endl;
17 cout << "Nuevo nombre: ";
18 cin >> inventario[posicion];
19
20 cout << "Posicion " << posicion << " actualizada correctamente." << endl;
21}

Delete: Eliminar con Desplazamiento Manual (Shift Left)

Si eliminamos el elemento en la posición 1 ("Pico"), no podemos dejar un hueco vacío en el medio. Debemos mover todos los elementos de la derecha una posición hacia la izquierda y luego decrementar cantidadInventario--:

// Ejemplo de desplazamiento al borrar el índice 1:Antes: [Espada(0)] [Pico(1)] [Madera(2)] [Pan(3)] (cantidad = 4)
Mover: inventario[1] = inventario[2] // Madera pasa a la pos 1
inventario[2] = inventario[3] // Pan pasa a la pos 2
Despues:[Espada(0)] [Madera(1)] [Pan(2)] (cantidad = 3)
Función eliminarObjeto con desplazamiento
CPP
1void eliminarObjeto(string inventario[], int& cantidadInventario) {
2 if (cantidadInventario == 0) {
3 cout << "El inventario ya esta vacio." << endl;
4 return;
5 }
6
7 int posicion;
8 cout << "Posicion a eliminar (0 a " << cantidadInventario - 1 << "): ";
9 cin >> posicion;
10
11 if (posicion < 0 || posicion >= cantidadInventario) {
12 cout << "Posicion fuera de rango." << endl;
13 return;
14 }
15
16 cout << "Eliminando " << inventario[posicion] << "..." << endl;
17
18 // Desplazar los elementos siguientes una posicion a la izquierda
19 for (int i = posicion; i < cantidadInventario - 1; i++) {
20 inventario[i] = inventario[i + 1];
21 }
22
23 // Reducir la cantidad ocupada en main
24 cantidadInventario--;
25
26 cout << "Objeto eliminado con exito." << endl;
27}

Search: Buscar Objeto (Retorno int)

Distinción pedagógica clave: las funciones void ejecutan una acción, mientras que una función de tipo int calcula y retorna un resultado (el índice encontrado o -1 si no existe).

Función buscarObjeto
CPP
1int buscarObjeto(string inventario[], int cantidadInventario, string itemBuscado) {
2 for (int i = 0; i < cantidadInventario; i++) {
3 if (inventario[i] == itemBuscado) {
4 return i; // Retorna la posicion donde fue encontrado
5 }
6 }
7 return -1; // -1 indica que el objeto no esta en el inventario
8}

6. Programa Completo: Menú Interactivo del Inventario

A continuación tienes el programa completo listo para copiar, compilar y ejecutar en tu entorno (Visual Studio, Code::Blocks, CLion o terminal con g++):

Gestor Completo de Inventario con Arreglos en C++
CPP
1#include <iostream>
2#include <string>
3
4using namespace std;
5
6const int CAPACIDAD = 9;
7
8// Declaración de funciones modulares
9void mostrarInventario(string inventario[], int cantidadInventario) {
10 if (cantidadInventario == 0) {
11 cout << "\n[!] El inventario esta vacio.\n";
12 return;
13 }
14 cout << "\n=== INVENTARIO DEL JUGADOR (" << cantidadInventario << "/" << CAPACIDAD << ") ===\n";
15 for (int i = 0; i < cantidadInventario; i++) {
16 cout << "[" << i << "] " << inventario[i] << "\n";
17 }
18 cout << "=======================================\n";
19}
20
21void agregarObjeto(string inventario[], int& cantidadInventario) {
22 if (cantidadInventario >= CAPACIDAD) {
23 cout << "\n[X] Error: El inventario esta lleno (Maximo 9 casillas).\n";
24 return;
25 }
26 string nuevo;
27 cout << "Nombre del nuevo objeto: ";
28 cin >> nuevo;
29
30 inventario[cantidadInventario] = nuevo;
31 cantidadInventario++;
32 cout << "[OK] " << nuevo << " agregado en la posicion " << cantidadInventario - 1 << ".\n";
33}
34
35void modificarObjeto(string inventario[], int cantidadInventario) {
36 if (cantidadInventario == 0) {
37 cout << "\n[!] No hay objetos para modificar.\n";
38 return;
39 }
40 int pos;
41 cout << "Indice a modificar (0 a " << cantidadInventario - 1 << "): ";
42 cin >> pos;
43
44 if (pos < 0 || pos >= cantidadInventario) {
45 cout << "[X] Indice invalido.\n";
46 return;
47 }
48 cout << "Reemplazando [" << inventario[pos] << "]. Ingrese nuevo nombre: ";
49 cin >> inventario[pos];
50 cout << "[OK] Posicion " << pos << " actualizada.\n";
51}
52
53void eliminarObjeto(string inventario[], int& cantidadInventario) {
54 if (cantidadInventario == 0) {
55 cout << "\n[!] El inventario esta vacio.\n";
56 return;
57 }
58 int pos;
59 cout << "Indice a eliminar (0 a " << cantidadInventario - 1 << "): ";
60 cin >> pos;
61
62 if (pos < 0 || pos >= cantidadInventario) {
63 cout << "[X] Posicion invalida.\n";
64 return;
65 }
66 cout << "[OK] " << inventario[pos] << " eliminado.\n";
67
68 // Desplazamiento manual hacia la izquierda
69 for (int i = pos; i < cantidadInventario - 1; i++) {
70 inventario[i] = inventario[i + 1];
71 }
72 cantidadInventario--;
73}
74
75int buscarObjeto(string inventario[], int cantidadInventario, string item) {
76 for (int i = 0; i < cantidadInventario; i++) {
77 if (inventario[i] == item) return i;
78 }
79 return -1;
80}
81
82int main() {
83 string inventario[CAPACIDAD] = { "Espada", "Pico", "Madera", "Pan", "Piedra", "Arco" };
84 int cantidadInventario = 6;
85 int opcion = 0;
86
87 do {
88 cout << "\n--- GESTOR DE INVENTARIO MINECRAFT ---\n";
89 cout << "1. Mostrar inventario\n";
90 cout << "2. Agregar objeto\n";
91 cout << "3. Modificar objeto\n";
92 cout << "4. Eliminar objeto\n";
93 cout << "5. Buscar objeto\n";
94 cout << "6. Salir\n";
95 cout << "Seleccione una opcion (1-6): ";
96 cin >> opcion;
97
98 switch (opcion) {
99 case 1:
100 mostrarInventario(inventario, cantidadInventario);
101 break;
102 case 2:
103 agregarObjeto(inventario, cantidadInventario);
104 break;
105 case 3:
106 modificarObjeto(inventario, cantidadInventario);
107 break;
108 case 4:
109 eliminarObjeto(inventario, cantidadInventario);
110 break;
111 case 5: {
112 string item;
113 cout << "Nombre del objeto a buscar: ";
114 cin >> item;
115 int pos = buscarObjeto(inventario, cantidadInventario, item);
116 if (pos != -1) {
117 cout << "[!] Encontrado en la posicion: " << pos << "\n";
118 } else {
119 cout << "[X] El objeto no esta en el inventario.\n";
120 }
121 break;
122 }
123 case 6:
124 cout << "Saliendo del juego... ¡Hasta la proxima aventura!\n";
125 break;
126 default:
127 cout << "[X] Opcion no valida, intente nuevamente.\n";
128 }
129 } while (opcion != 6);
130
131 return 0;
132}
🚀 Siguiente Nivel Pedagógico

El Gran Dilema: ¿Por qué los Arreglos Fijos se Quedan Cortos?

Como acabas de ver, trabajar con arreglos tradicionales nos obligó a:

  • 1.Tener un límite estricto de 9 posiciones. Si el jugador encuentra un cofre o mochila, el arreglo no puede crecer.
  • 2.Administrar manualmente dos variables por separado (inventario[9] y cantidadInventario).
  • 3.Escribir bucles complejos para desplazar elementos uno a uno cada vez que borramos un ítem.

¿No sería genial si C++ pudiera encargarse automáticamente del tamaño, inserción y borrado de elementos sin límites fijos?

Dato curioso: C++ apareció en 1985; Bjarne Stroustrup en Bell Labs. Wikipedia

Ko-fi
Donaciones
Apoyá cafeycodigo con un café en Ko-fi. Colaboradores: insignia, muro y zona exclusiva.