thecodingidiot.com

Writing CFunctions

Functions

A function is a named block of code that you can call by name, pass values to, and receive a result from. Functions let you name an idea, then use that name instead of repeating the implementation.

Declaration and definition

A declaration tells the compiler a function exists and what its signature is. A definition provides the body.

/* declaration — the compiler now knows add() exists */
int add(int a, int b);
 
/* definition — the implementation */
int add(int a, int b)
{
    return (a + b);
}

In a single-file program the definition alone is sufficient — the compiler reads top to bottom, so put the function before main or add a declaration above main. The end of this page shows what to do when a project grows beyond a single file.

Return values and parameters

The type before the function name is the return type. A function that returns nothing uses void:

void print_separator(void)
{
    printf("────────────\n");
}

Parameters are copies — C passes by value. Changing a parameter inside a function does not affect the caller's variable:

void double_it(int n)
{
    n = n * 2;   /* changes the local copy only */
    printf("%d\n", n);
}
 
int main(void)
{
    int x = 5;
    double_it(x);
    printf("%d\n", x);   /* still 5 */
    return (0);
}

To modify the caller's variable you need a pointer — that is c01 territory. For now, functions receive values and return values.

Scope

Scope is the region of a program where a variable exists and can be used. A variable declared inside a function is local to that function — it is created when the function is called and destroyed when the function returns. Nothing outside the function can see it, and it does not persist between calls.

int add(int a, int b)
{
    int result;
    result = a + b;
    return (result);
}   /* result ceases to exist here */

This also means two functions can use the same variable names without any conflict:

int add(int a, int b)
{
    int result = a + b;
    return (result);
}
 
int multiply(int a, int b)
{
    int result = a * b;   /* a different result, in a different function */
    return (result);
}

Each result belongs to its own function. They never see each other. This is what makes functions safe to write independently — you do not need to know or care what names other functions use.


Refactoring the calculator

Replace the if/else chain with one function per operation. Each function takes two int parameters and returns an int.

#include <stdio.h>
 
int add(int a, int b)
{
    return (a + b);
}
 
int subtract(int a, int b)
{
    return (a - b);
}
 
int multiply(int a, int b)
{
    return (a * b);
}
 
int divide(int a, int b)
{
    return (a / b);
}
 
int main(void)
{
    int  a;
    int  b;
    char op;
 
    printf("Enter: number operator number (e.g. 3 + 4)\n");
    scanf("%d %c %d", &a, &op, &b);
    if (op == '+')
        printf("%d %c %d = %d\n", a, op, b, add(a, b));
    else if (op == '-')
        printf("%d %c %d = %d\n", a, op, b, subtract(a, b));
    else if (op == '*')
        printf("%d %c %d = %d\n", a, op, b, multiply(a, b));
    else if (op == '/') {
        if (b == 0) {
            printf("Error: division by zero\n");
            return (1);
        }
        printf("%d %c %d = %d\n", a, op, b, divide(a, b));
    }
    else {
        printf("Error: unknown operator '%c'\n", op);
        return (1);
    }
    return (0);
}

Each operation is now a single readable line. Adding % (modulo) means writing one more function and one more else if. The logic is contained.


Header files

When a project spans multiple .c files, declarations go in a .h header that every file includes. A header is not magic — it is a text file the preprocessor pastes into your source before compilation.

For a project this small, a single file is fine. But the pattern is worth seeing once:

calculator.h:

#ifndef CALCULATOR_H
#define CALCULATOR_H
 
int add(int a, int b);
int subtract(int a, int b);
int multiply(int a, int b);
int divide(int a, int b);
 
#endif

calculator.c:

#include "calculator.h"
#include <stdio.h>
 
int add(int a, int b)
{
    return (a + b);
}
/* ... */

main.c:

#include "calculator.h"
#include <stdio.h>
 
int main(void)
{
    printf("%d\n", add(3, 4));
    return (0);
}

Compile with both files:

gcc -Wall -Wextra main.c calculator.c -o calculator

The #ifndef / #define / #endif guard prevents the header from being included twice if multiple files include it. You will see this pattern in every C project. f05 covers multi-file projects and Makefiles in depth — for now, single-file is sufficient.

Your calculator.c for the tester can be the single-file version from this page. The functions are there; the structure is there.