Skip to Content
Course content

233: Practice Exercise: Simple Command-Line Todo List in C

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Think of building a todo list in C like keeping a handwritten ledger in a physical notebook. You have a fixed number of pages (your array size), and each line on the page has a specific format: a checkbox and a space for the task description. When you add a task, you find the first empty line and write it down. When you finish a task, you don't usually rip the page out; you just check the box. If you absolutely have to remove a task to make room, you have to erase it and physically shift every subsequent line up to fill the gap.

In our C code, we map these physical actions directly to memory management. That "line in the notebook" becomes a struct. The "fixed number of pages" is a statically allocated array of those structs. Checking the box is just flipping a boolean or an integer from 0 to 1. And that tedious process of shifting lines? That's a for loop moving elements in your array to avoid leaving "holes" in your data.

Defining the Blueprint for a Task

You can't just throw strings into an array if you want to track whether a task is finished. I always recommend using a struct here. It keeps the description and the status bundled together so they don't get out of sync. I like to keep the description length fixed—say, 100 characters—to avoid the headache of malloc and free for a simple exercise like this. It's not the most memory-efficient way, but for a CLI tool, it's plenty.

typedef struct {
    char description[100];
    int is_done;
} TodoItem;

Handling the Input Friction

Here is where most people trip up: scanf. If you use scanf("%s", ...) to get a task description, it will stop reading the moment it hits a space. Your "Buy milk" task becomes just "Buy". To fix this, I use fgets. It reads the whole line, including the spaces. Just be mindful that fgets also grabs the newline character \n when you hit Enter, so you'll want to strip that out manually if you care about your formatting looking clean.

Managing the List State

Since we're using a fixed array, you need a separate variable to track how many tasks are actually in the list. I call this task_count. When you add a task, you place it at index task_count and then increment the counter. When you delete a task at index i, you have to run a loop from i to task_count - 1, moving every item one slot to the left. It feels clunky, but that's the reality of contiguous memory in C.

for (int i = index_to_remove; i < task_count - 1; i++) {
    tasks[i] = tasks[i + 1];
}
task_count--;

I've found that the most satisfying part of this exercise isn't the logic itself, but building the "Command Loop." You wrap everything in a while(1) loop, present a small menu, and use a switch statement to handle the user's choice. It turns a collection of functions into an actual piece of software you can interact with.




📋 Practical Task

Build the "Get-It-Done" CLI Task Manager

Your goal is to implement a fully functional command-line todo list. Create a program that satisfies the following requirements:

  • Storage: Use an array of structs capable of holding up to 10 tasks. Each struct should have a string for the task and an integer for the completion status.
  • The Menu: Implement a loop that allows the user to:
    1. Add a new task (ensure it handles spaces in the task description).
    2. List all current tasks, showing their index and whether they are [ ] incomplete or [X] complete.
    3. Mark a specific task as complete by its index.
    4. Delete a task entirely, shifting subsequent tasks up to fill the gap.
    5. Exit the program.
  • Edge Cases: Your code must prevent the user from adding tasks beyond the array limit and prevent them from marking or deleting a task index that doesn't exist.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.