Skip to main content

Function Prototypes and Variable Scope – How C Organizes Code

Updated 4 min readMarkdown
Part of seriesC Programming

In the previous lesson, you learned how to:

  • Define functions

  • Call functions

  • Use parameters

  • Return values

Now we go one level deeper.

Today we will understand:

  • Why function prototypes exist

  • How the compiler reads your code

  • The difference between declaration and definition

  • Local vs global variables

This lesson helps you understand how C really works behind the scenes.

1. How the Compiler Reads Your Code

The C compiler reads your file from top to bottom.

It does not “look ahead” to guess what you mean.

If you call a function before the compiler has seen it, it will complain.

Example:

#include <stdio.h>

int main() {
    int result = add(2, 3);
    printf("%d\n", result);
    return 0;
}

int add(int a, int b) {
    return a + b;
}

This may cause an error because when the compiler reaches add(2, 3), it has not yet seen the function definition.

It doesn’t know what add is.

So what do we do?

We use a function prototype.

2. What Is a Function Prototype?

A function prototype is a declaration that tells the compiler:

“This function exists, and this is what it looks like.”

It includes:

  • Return type

  • Function name

  • Parameter types

But no function body.

Example:

int add(int a, int b);

That semicolon at the end is important.

3. Declaration vs Definition

This is very important.

Function Declaration (Prototype)

Blueprint only:

int add(int a, int b);

It tells the compiler:

  • The function name is add

  • It returns an int

  • It takes two int parameters

But it does not contain the actual code.

Function Definition

Actual implementation:

int add(int a, int b) {
    return a + b;
}

This contains the real instructions.

Think of it like this:

Declaration → “This function exists.”
Definition → “This is how it works.”

4. Correct Program Structure

Here is the proper structure:

#include <stdio.h>

int add(int a, int b);  // Prototype

int main() {
    int result = add(2, 3);
    printf("%d\n", result);
    return 0;
}

int add(int a, int b) {  // Definition
    return a + b;
}

Now when the compiler reads the file:

  1. It sees the prototype.

  2. It knows add exists.

  3. It allows main() to call it.

  4. Later it finds the definition.

No error.

5. Variable Scope

Now let’s talk about scope.

Scope determines:

Where a variable can be accessed.

There are two main types:

  • Local variables

  • Global variables

6. Local Variables

Local variables are declared inside a function.

They only exist inside that function.

Example:

#include <stdio.h>

void greet() {
    int x = 10;
    printf("%d\n", x);
}

int main() {
    greet();
    // printf("%d\n", x);  // This would cause an error
    return 0;
}

Why does this cause an error?

Because x only exists inside greet().

Once the function finishes, x is destroyed.

7. Global Variables

Global variables are declared outside all functions.

They can be accessed from any function.

Example:

#include <stdio.h>

int globalVar = 10;

void greet() {
    printf("%d\n", globalVar);
}

int main() {
    greet();
    printf("%d\n", globalVar);
    return 0;
}

Both functions can use globalVar.

8. Should We Use Global Variables?

Yes, but carefully.

Global variables:

  • Make code harder to manage

  • Can be modified anywhere

  • Can cause bugs

Best practice:
Use local variables whenever possible.

9. Common Function and Scope Errors

Students often see errors like:

  • “Implicit declaration of function”

  • “Undefined reference”

  • “Conflicting types”

  • Using a variable outside its scope

  • Missing return statement

When you see errors:

  1. Read the first error carefully.

  2. Look at the line number.

  3. Fix one error at a time.

10. Putting It All Together

Example combining everything:

#include <stdio.h>

int multiply(int a, int b);  // Prototype

int main() {
    int result = multiply(4, 5);
    printf("Result: %d\n", result);
    return 0;
}

int multiply(int a, int b) {
    int product = a * b;  // Local variable
    return product;
}

What we see here:

  • Prototype at the top

  • main() calls function

  • Local variable inside function

  • Proper return type

  • Clean structure

Final Thoughts

Today you learned:

  • The compiler reads top to bottom

  • Declaration is not the same as definition

  • Prototypes prevent errors

  • Scope controls where variables can be used

  • Local variables are safer than global variables

Now you understand how C organizes programs.

You are no longer just writing code.

You are structuring programs properly.

About the author

  • Heya! 👋 I love helping people, and one of the best ways I do this is by sharing what I learn and build. I started as a pharmacist at a tertiary hospital in Northern Ghana, where I saw how much technology could improve healthcare. That sparked my interest in digital health. I taught myself to code, then joined the ALX Software Engineering program, which became a turning point. I went on to complete a Master of Health Informatics at the University of Toronto. Today I am a software and AI engineer and a health informatician, and I practise remotely as a Digital Health Pharmacist. I combine clinical experience with technical skills to build tools that solve real problems in health and beyond, and I write here about what I build and what I learn.

No comments yet. Be the first to comment.

C Programming

Part 18 of 40

From today, I will be starting lessons on C programming in my ALX Software Engineering class and I look forward to sharing with you everything I learn through this series.

Up nextArrays – Storing Data in Blocks of MemorySo far, we’ve been working with single variables: int age = 20; int score = 85; That works fine when you only need one value. But what if you need to store: 5 test scores? 10 student IDs? 100 numb

More from this blog