Skip to Content
Course content

27: Declaring and Defining Functions

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

You've probably noticed by now that C is a bit of a perfectionist. It wants to know everything about a function—what it returns and what it takes as arguments—before you actually try to call it. If you don't give it that information, the compiler starts guessing, and in C, guessing is usually a recipe for a segmentation fault or a very confusing warning about "implicit declaration."

The "Just Put it Above Main" Trap

When you're first starting out, the easiest way to make the compiler happy is to simply define your functions before the main() function. It looks like this:

float calculate_damage(float base, float multiplier) {
    return base * multiplier;
}

int main() {
    float final_dmg = calculate_damage(10.0f, 1.5f);
    return 0;
}

For a tiny script, this is fine. I've done it myself for quick prototypes. But as your project grows, you'll hit a wall. Imagine you have a take_damage() function that calls calculate_damage(), but calculate_damage() needs to call a get_armor_reduction() function. Suddenly, you're playing a game of "musical chairs" with your code, shifting function blocks up and down the file just to satisfy the compiler's need to see a definition before a call. If function A calls B, and B calls A, you're stuck. There is no order that works.

Breaking the Dependency Chain

This is where we separate the declaration from the definition. A declaration (or a prototype) is essentially you telling the compiler: "Hey, there is a function with this name, it takes these types of arguments, and it returns this type. I'm not going to tell you how it works right now, but trust me, it exists somewhere."

By placing a prototype at the top of your file, you break the dependency chain. You can put your main() function at the very top of the file—which is where I personally prefer it, so I don't have to scroll through 500 lines of helper functions to find the entry point—and define the actual logic wherever it makes sense.

// Declarations (The "What")
float calculate_damage(float base, float multiplier);
float apply_armor(float damage, float armor_value);

int main() {
    float raw = calculate_damage(10.0f, 1.5f);
    float final = apply_armor(raw, 5.0f);
    return 0;
}

// Definitions (The "How")
float calculate_damage(float base, float multiplier) {
    return base * multiplier;
}

float apply_armor(float damage, float armor_value) {
    return damage - armor_value;
}

The Trade-off: Maintenance vs. Flexibility

Now, you might ask: "Why not just stick to the naive way if it's less typing?" The trade-off here is maintenance. Every time you change a function's signature—say, you decide calculate_damage needs a third argument for "critical hit chance"—you now have to update it in two places: the declaration at the top and the definition at the bottom.

It feels like extra work, but it's a necessary evil. This separation is exactly how header files (.h) work. When you include <stdio.h>, you aren't importing the actual code for printf(); you're importing a list of declarations. The actual definitions are tucked away in a pre-compiled library. By practicing this in a single file now, you're training your brain for the way professional C projects are structured across dozens of different files.




📋 Practical Task

Building a Combat Damage Calculator

Create a program that simulates a simple RPG damage calculation. To practice the separation of declaration and definition, you must follow these constraints:

  • Place your main() function at the top of the file.
  • Create two functions: float calculate_crit(float base_dmg) (which should return the damage multiplied by 2.0) and float calculate_mitigation(float dmg, float defense) (which should subtract the defense value from the damage).
  • Ensure both functions have prototypes at the top of the file so main() can call them.
  • In main(), call calculate_crit first, pass that result into calculate_mitigation, and print the final result.
  • Define the actual function logic below the main() function.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.