Skip to Content
Course content

34: Practice Exercise: Building a Simple Math Utility Library

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

Imagine you're a professional carpenter. You don't forge a new hammer or carve a new screwdriver out of raw steel every single time you start a project. That would be a complete waste of time. Instead, you have a tool chest. You know exactly where the hammer is, you know what it does, and you don't really care about the molecular structure of the steel used to make it—you just care that it drives the nail straight.

In C, building a utility library is exactly like organizing that tool chest. The header file (.h) is like the labels on your drawers; it tells you what tools are available and how to use them. The source file (.c) is the actual tool itself—the heavy lifting and the logic. By separating them, you can use your "tools" across ten different projects without ever having to rewrite the logic for how to calculate a power or a percentage.

Designing the Interface Contract

When I'm designing a library, I think of the header file as a contract. I'm telling whoever uses this code, "If you provide me with these specific inputs, I promise to give you this specific result." You don't put the actual logic here; you only put the function prototypes.

Don't forget the header guards. I've seen far too many beginners run into "redefinition" errors because they included the same header twice. Using #ifndef, #define, and #endif is non-negotiable in a real-world project.

// math_utils.h
#ifndef MATH_UTILS_H
#define MATH_UTILS_H

double power(double base, int exp);
double average(double numbers[], int count);
int is_even(int num);

#endif

Bringing the Logic to Life

Now we move to the .c file. This is where the actual "manufacturing" happens. This file must include your header so the compiler can verify that your implementation matches the contract you just signed in the .h file.

Keep your functions focused. A utility library fails when functions try to do too much. If a function is called average, it should calculate an average and nothing else—no printing to the console, no input validation from the user. Just pure math.

// math_utils.c
#include "math_utils.h"

double power(double base, int exp) {
    double result = 1.0;
    for (int i = 0; i < exp; i++) {
        result *= base;
    }
    return result;
}

double average(double numbers[], int count) {
    if (count <= 0) return 0.0;
    double sum = 0;
    for (int i = 0; i < count; i++) {
        sum += numbers[i];
    }
    return sum / count;
}

int is_even(int num) {
    return num % 2 == 0;
}

Connecting the Parts in Main

To actually use this, your main.c only needs to know about the header. It doesn't need to see the internal loop of the power function; it just trusts the interface. When you compile, you'll need to tell the compiler to link both .c files together. If you're using GCC, it looks something like gcc main.c math_utils.c -o my_program.

I personally find this separation satisfying because it cleans up the "noise" in my main logic. My main() function starts looking like a high-level description of a problem rather than a jungle of mathematical implementation details.

// main.c
#include 
#include "math_utils.h"

int main() {
    double vals[] = {10.5, 20.0, 30.5};
    printf("Average: %.2f\n", average(vals, 3));
    printf("2 to the 4th: %.2f\n", power(2, 4));
    
    return 0;
}



📋 Practical Task

Exercise: Expanding the Math Utility Library with Statistical Helpers

Your goal is to extend the math_utils library we just discussed. Instead of just basic arithmetic, you need to add a few "statistical" tools to the chest.

  • Modify math_utils.h: Add prototypes for two new functions:
    • double find_max(double arr[], int size): Returns the largest value in an array.
    • double clamp(double value, double min, double max): Returns the value, but ensures it doesn't go below the min or above the max (very useful for game physics or sensor data).
  • Modify math_utils.c: Implement the logic for these two functions. Ensure find_max handles empty arrays gracefully (return 0.0 or a specific error value).
  • Create a test program: In your main.c, create an array of doubles and use find_max to locate the highest number. Then, try to clamp a value of 150.0 between a min of 0.0 and a max of 100.0 to verify it correctly returns 100.0.

Compile the project by linking both source files together and verify the output.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.