Introduction
In our previous lesson, we designed the core data structures for a game inventory, establishing the Item and Inventory structs and sketching out the primary functions to manage them. You saw a first-pass implementation of adding, removing, and displaying items, which covered the architectural design.
Today, we will transition from that initial design to a more robust, practical implementation. We will refine the functions for adding, displaying, and, most importantly, removing items from our array-based inventory. This lesson focuses on the "how" by examining different strategies for these common operations, including their performance trade-offs—a key aspect of low-level programming. By the end, you'll have a complete, runnable C program that demonstrates a functional inventory system, setting the stage for more complex game mechanics.
The Core Operations: A Refresher
The utility of any data structure is defined by the functions that manipulate it. For our inventory, the essential operations are displaying its contents, adding new items, and removing existing ones. Let's solidify our understanding of how to implement these for a static array.
A core pattern you'll see is iterating through the array. The following video demonstrates this principle for both input and output, which is directly applicable to our add and display functions.
C_112 Array of Structures in C | C Language Tutorials
This video from Jenny's Lectures CS IT clearly shows the logic for using loops to handle an array of structs, both for reading data in and printing it out.
Watch the section on program logic. Notice how a for loop combined with an index i is the standard way to process each element in sequence, using the s[i].member syntax to access data. This is precisely the technique we use for our inventory.
With that looping pattern in mind, let's look at each function.
Displaying and Adding Items
In the last lesson, we outlined functions for these tasks. The logic is straightforward:
display_inventory: Loop from0toinv->count - 1and print the details ofinv->items[i].add_item: Check ifinv->countis less thanINVENTORY_CAPACITY. If it is, place the new item atinv->items[inv->count]and then incrementinv->count.
This approach is standard for managing a collection in a fixed-size array. You can see this exact logic for adding an item in a Stack Overflow answer discussing this common problem.
Array of structs - deleting/adding elements and printing
This forum answer provides a concise, real-world example of managing a static array of structs.
Focus on the add_item function. Notice how it takes a pointer to the array, the new item, and a pointer to the item counter. It checks for capacity (< MAX_ITEMS), adds the item to the end of the currently-used portion of the array, and increments the counter. This confirms the validity of the approach we designed.
The Nuances of Removal: Two Strategies
While adding and displaying are relatively simple, removing an item from an array presents a choice. The "right" method depends on whether the order of items in the inventory matters for your game. Let's explore two common strategies.
Strategy 1: The Shifting Method (Preserves Order)
This is the method we implemented in the previous lesson. The process is:
- Find the index of the item to be removed.
- Starting from that index, loop through the rest of the array, shifting each subsequent element one position to the left (
array[i] = array[i + 1]). - Decrement the total item count.
This method ensures that the relative order of the remaining items is preserved. If a player organizes their inventory, this behavior would be expected.

The main drawback is performance. If you remove an item from the beginning of a large array, you have to move every other element, resulting in an operation with O(N) time complexity. For a small inventory, this is negligible, but for managing thousands of objects, it could become a bottleneck.
Strategy 2: The Swap-and-Pop Method (Performance-focused)
If the order of items in the inventory doesn't matter, there's a much faster way to remove an element.
- Find the index
kof the item to be removed. - Take the last valid item in the array (at index
count - 1) and copy it over the item at indexk. - Decrement the total item count.
This is extremely efficient. After finding the item (which takes O(N) time), the removal itself is a single copy operation, making it O(1). This is often called the "swap and pop" or "move-last" trick.
The following resource shows this technique in a worked example.
C Array of Structures - Programming and Cloud Tutorials
This tutorial page includes a complete mini-program for CRUD (Create, Read, Update, Delete) operations. While it uses dynamic memory (which we'll cover later), its remove_by_id function perfectly demonstrates the swap-and-pop technique.
Examine the remove_by_id function in the "Worked mini-program" section. The key line is a[k] = a[pn - 1];. It overwrites the element to be deleted (a[k]) with the last element (a[pn-1]), effectively removing it in a single step before decrementing the count pn.
For most game inventories, order doesn't matter, making the swap-and-pop method the superior choice for its efficiency.
Putting It All Together: A Working Program
Now, let's integrate these refined functions into a complete, runnable program. The code below uses the data structures from our last lesson but implements the remove_item function using the more efficient swap-and-pop method.
#include <stdio.h>
#include <string.h>
// Game parameters defined as constants
#define MAX_NAME_LENGTH 50
#define INVENTORY_CAPACITY 10
// Enum for item categorization
typedef enum {
ITEM_WEAPON,
ITEM_ARMOR,
ITEM_POTION,
ITEM_MISC
} ItemType;
// Struct for a single item
typedef struct {
char name[MAX_NAME_LENGTH];
ItemType type;
int value;
float weight;
} Item;
// Struct for the inventory
typedef struct {
Item items[INVENTORY_CAPACITY];
int count;
} Inventory;
// Function Prototypes
void initialize_inventory(Inventory *inv);
void display_inventory(const Inventory *inv);
int add_item(Inventory *inv, Item newItem);
int remove_item(Inventory *inv, const char *name); // Using swap-and-pop
// --- Main Program ---
int main() {
Inventory player_inventory;
initialize_inventory(&player_inventory);
printf("--- Initializing Inventory ---\n");
display_inventory(&player_inventory);
// Create some items to add
Item sword = {"Iron Sword", ITEM_WEAPON, 50, 10.0f};
Item shield = {"Wooden Shield", ITEM_ARMOR, 25, 12.0f};
Item potion = {"Health Potion", ITEM_POTION, 10, 0.5f};
Item junk = {"Old Boot", ITEM_MISC, 1, 1.5f};
printf("\n--- Adding Items ---\n");
add_item(&player_inventory, sword);
add_item(&player_inventory, shield);
add_item(&player_inventory, potion);
add_item(&player_inventory, junk);
printf("\n--- Current Inventory ---\n");
display_inventory(&player_inventory);
printf("\n--- Removing 'Wooden Shield' (Swap-and-Pop) ---\n");
remove_item(&player_inventory, "Wooden Shield");
printf("\n--- Final Inventory ---\n");
display_inventory(&player_inventory);
return 0;
}
// --- Function Definitions ---
void initialize_inventory(Inventory *inv) {
inv->count = 0;
}
void display_inventory(const Inventory *inv) {
printf("Inventory (%d/%d):\n", inv->count, INVENTORY_CAPACITY);
if (inv->count == 0) {
printf(" -> Empty\n");
return;
}
for (int i = 0; i < inv->count; i++) {
printf(" -> %s (Value: %d, Weight: %.2f)\n",
inv->items[i].name,
inv->items[i].value,
inv->items[i].weight);
}
}
int add_item(Inventory *inv, Item newItem) {
if (inv->count >= INVENTORY_CAPACITY) {
printf("Error: Inventory is full. Cannot add %s.\n", newItem.name);
return 0; // Failure
}
inv->items[inv->count] = newItem;
inv->count++;
printf("'%s' added to inventory.\n", newItem.name);
return 1; // Success
}
// Implementation of the Swap-and-Pop removal strategy
int remove_item(Inventory *inv, const char *name) {
int found_index = -1;
// 1. Find the item
for (int i = 0; i < inv->count; i++) {
if (strcmp(inv->items[i].name, name) == 0) {
found_index = i;
break;
}
}
if (found_index == -1) {
printf("Error: Item '%s' not found.\n", name);
return 0; // Not found
}
// 2. If the item is not the last one, swap it with the last item
int last_index = inv->count - 1;
if (found_index != last_index) {
printf("Swapping '%s' with last item '%s'.\n", inv->items[found_index].name, inv->items[last_index].name);
inv->items[found_index] = inv->items[last_index];
}
// 3. Decrement the count, effectively "popping" the last element
inv->count--;
printf("'%s' successfully removed.\n", name);
return 1; // Success
}
Compile and run this code. Observe the output when remove_item is called. The "Old Boot", which was the last item, moves into the "Wooden Shield"'s old slot. The order is changed, but the removal was accomplished with a single, efficient copy operation.
Conclusion
In this lesson, you have moved from a high-level design to a concrete, functional implementation of an inventory system. You've now written and refined the three crucial functions—add, remove, and display—that bring the data structure to life.
Key Takeaways:
- Adding items to a static array-based inventory involves appending to the end of the used portion and incrementing a counter.
- Removing an item can be done in two main ways:
- Shifting: Preserves item order but is less performant (O(N)).
- Swap-and-Pop: Breaks item order but is highly performant (O(1) after finding the item).
- The choice between removal strategies is a classic engineering trade-off between functionality (preserving order) and performance. For many game systems, performance wins.
- Combining data structures with a suite of functions that operate on them is the fundamental pattern for building complex systems in C.
Our inventory system is now functional. In the next lesson, we'll build another core piece of our game: a combat loop. You will see how this inventory can be used within that loop, for example, allowing a player to use a Health Potion during a fight, connecting these two essential game systems.