Say Goodbye to Long and Clumsy If-Else Statements! A Practical Guide to Table-Driven Methods in C Language

Say Goodbye to Long and Clumsy If-Else Statements! A Practical Guide to Table-Driven Methods in C Language

Today, we won’t waste time on small talk; let’s dive directly into a design principle that isextremely important in program design — the Table-Driven Method (Table-Driven Methods).

Many students, when writing code, encounter multiple branching conditions and their first reaction is to write a bunch of if-else or switch-case. While writing, it feels logical, but after a few days, looking back: this code is just too “stupid” and long, making it hard to maintain.

In this lesson, we will explore the charm of the Table-Driven Method through two classic cases — “Calculating the Number of Days in a Month” and “Grade Evaluation”. Mastering this technique will instantly elevate the quality of your code!

01

Getting the Number of Days in a Month (Pain Points of Traditional Methods)

We need to write a function that takes a year and a month as input and returns how many days are in that month.

According to the most basic logic of a beginner, the code might look like this:

int get_days_original(int month, int year) {    if (month < 1 || month > 12) {        return -1; // Invalid month    }    if (month == 1) return 31;    else if (month == 2) {        // Here we also need to check for leap years, nesting the logic again        if (is_leap_year(year)) return 29;        else return 28;    }    else if (month == 3) return 31;    // ... and a long string follows ...    else if (month == 12) return 31;    return 0;}

Do you see this code? Doesn’t it make your blood pressure rise?

If there are only a few branches, it’s fine, but if you have to handle dozens of conditions, this code is simply a “disaster”. Moreover, if you write another set of leap year checking logic inside month == 2, the readability of the code drops to negative.

What is the Table-Driven Method?

The Table-Driven Method is an extremely powerful programming technique. Its core idea is very simple:

Use data structures (like arrays, hash tables) to replace complex logical control statements (if-else/switch).

In simple terms, it transforms “logic” into “data”. The program does not need to “judge” what to do, but directly “look up the table” to get the result.

02

Refactoring Practice: Using “Table Lookup” to Outperform If-Else

Let’s see how to rewrite the above logic using the Table-Driven Method.

First, we need a helper function to determine if a year is a leap year. Here we optimize the traditional logic with one line of code (we won’t expand on elementary math problems, just the optimal solution):

// Determine if it is a leap year: divisible by 4 but not by 100, or divisible by 400int is_leap_year(int year) {    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);}

Next is the main event. Instead of writing if (month == 1), we establish an array that directly stores the number of days for the 12 months.

Look at the code, pay attention to how I handle the special case of February:

#define MONTH_COUNT 12int get_days_in_month(int month, int year) {    // Core technique: use an array as a lookup table    // The number of days in February depends on whether it is a leap year, here we use a ternary operator to generate it dynamically    const int days_in_month[MONTH_COUNT] = {        31,        is_leap_year(year) ? 29 : 28,         31, 30, 31, 30,         31, 31, 30, 31, 30, 31    };    // 1. Boundary check (this step cannot be omitted!)    if (month < 1 || month > MONTH_COUNT) {        return -1;    }    // 2. Directly look up the table and return    // Note: array index starts from 0, so use month - 1    return days_in_month[month - 1];}

Code analysis and professional correction:

Everyone pay attention to lines 107 to 111 in the original video. We condensed the originally complex logical checks into an array initialization.

Here is a technical detail that needs to correct a misconception:

Although we placed days_in_month inside the function for demonstration purposes and used the variable year for dynamic initialization, in performance-critical embedded or low-level development, the most standard “table-driven” would typically define this table as static const (static constant), placed in the data segment.

If it is a static table, how do we store the data for February?

Usually, we store 28, and then add a simple check in the code:if (month == 2 && is_leap_year(year)) return 29;. But for beginners, the above method is the most intuitive, and there is nothing wrong with it!

After this rewrite, no matter how the month changes, we only need one line of code return days_in_month[month – 1]; to get the result. Isn’t that just delightful?

03

Advanced Case: Grade Evaluation (Range Mapping)

The previous example was a “one-to-one” mapping (January corresponds to 31 days). But what if it is a “range mapping”?

Requirements:

  • 90-100 points -> A

  • 80-89 points -> B

  • 70-79 points -> C

  • 60-69 points -> D

  • 0-59 points -> F

Using the old-fashioned method, you would definitely write if (score >= 90). However, using the Table-Driven Method, we can find a “key” to connect the score and the grade.

This “key” is — the score divided by 10.

Let’s look at this extremely clever code:

#define GRADE_COUNT 11// Note: To support grades like "A+" which have two characters, the return type is changed to char* (string pointer)// If only returning 'A', 'B', char would suffice. Here we make an advanced optimization.const char* get_grade(int score) {    // Define lookup table    // Index represents the result of score/10    // 0-5 corresponds to F, 6 corresponds to D, 7 corresponds to C, 8 corresponds to B, 9 corresponds to A, 10 corresponds to A+    static const char* grades[GRADE_COUNT] = {        "F", "F", "F", "F", "F", "F", // 0~59 points / 10 results in 0~5        "D",                          // 60~69 points / 10 = 6        "C",                          // 70~79 points / 10 = 7        "B",                          // 80~89 points / 10 = 8        "A",                          // 90~99 points / 10 = 9        "A+"                          // 100 points / 10 = 10    };    // 1. Extremely important boundary check    // This is a basic quality of an excellent programmer, preventing array out-of-bounds access that could crash the program    static const char* invalid_grade = "Invalid";    if (score < 0 || score > 100) {        return invalid_grade;    }    // 2. Lookup table    // Using the property of integer division to round down, mapping the range to the index    return grades[score / 10];}

In-depth analysis: Why is this code “advanced”?

1. Application of Data Regularity

For scores from 90 to 99, the result of dividing by 10 is always 9; for scores from 80 to 89, the result is always 8. By utilizing the property of integer division, we compress a continuous range into a discrete index..

2. Is 100 points a special case?

Some students may ask, what if 100 divided by 10 is 10, and there is no corresponding index?

This reflects the rigor of design. Our GRADE_COUNT is defined as 11, with an index range of 0-10. This perfectly leaves a spot for 100 points (Index 10), which we assign to “A+”. A perfect loop!

3. Strings vs Characters

Careful students will notice that I changed the return type to const char*, and the elements in the array became double-quoted “A”.

This is to solve the problem mentioned at the end of the video: if you want to output “A+” (two characters), a single-quoted char type cannot hold it (it can only hold one byte). Using a string pointer not only allows for “A+”, but also makes it easy to store “Excellent” in the future, providing great extensibility.

04

Conclusion

The Table-Driven Method is not just a technique in C language; it is a design pattern applicable to all programming languages. When you find that your code has the following situations, think of it immediately:

  1. There are a large number of if-else or switch branches in the logic.

  2. There is some mapping relationship between input variables and output results (even if it is a range mapping).

  3. You need to frequently modify business logic (for example, changing the number of days in a month; modifying numbers in a table is much safer than changing if conditions).

Core Idea:

Many complex behaviors of programs can essentially be determined by “looking up tables” rather than through complex logical calculations.

Say Goodbye to Long and Clumsy If-Else Statements! A Practical Guide to Table-Driven Methods in C Language

Leave a Comment