Programs in many files

Real programs are too big for one file. In C, each part of a program gets two files:

  • a header (stack.h): the declarations, saying what other files can use;
  • a source file (stack.c): the definitions, saying how it works.

A stack in three files

/* stack.h */
#ifndef STACK_H
#define STACK_H

void push(int x);
int pop(void);
int size(void);

#endif
/* stack.c */
#include "stack.h"

static int items[100];   /* static: no other file can see these */
static int count = 0;

void push(int x) { items[count++] = x; }
int pop(void) { return items[--count]; }
int size(void) { return count; }
/* main.c */
#include <stdio.h>
#include "stack.h"

int main(void) {
    push(4);
    ...
}
  • #include "stack.h" with quotes looks in your folder first; <stdio.h> with angle brackets looks only in the system folders.
  • #include just pastes the file in. The include guard (#ifndef STACK_H ... #endif) makes sure the header is pasted only once, even if two files include it. Many compilers also accept #pragma once.
  • static on a global variable or function makes it private to its file. main.c cannot touch items directly; it must call push and pop.
  • Put declarations in headers, never definitions with bodies or variables with values: a header included by two files would define them twice.

Compiling the parts

gcc -Wall main.c stack.c -o app      # all at once

gcc -Wall -c stack.c                 # or one at a time: makes stack.o
gcc -Wall -c main.c                  # makes main.o
gcc main.o stack.o -o app            # link them into one program

Compiling separately means that when you change main.c, only main.c is compiled again. In a project with hundreds of files, that saves minutes on every build. The next lesson lets a tool decide what to rebuild.

The same program in one file

#include <stdio.h>

/* ---- stack.h: what other files may use ---- */
void push(int x);
int pop(void);
int size(void);

/* ---- stack.c: how it works ---- */
static int items[10];
static int count = 0;

void push(int x) { items[count++] = x; }
int pop(void) { return items[--count]; }
int size(void) { return count; }

/* ---- main.c: the program ---- */
int main(void) {
    push(4);
    push(7);
    push(1);
    while (size() > 0) {
        printf("%d ", pop());
    }
    printf("\n");
    return 0;
}
Open in compiler

StepVioz runs one file at a time, so here the three files are joined, with comments where each one starts. Watch items and count: they are globals, but nothing in the main.c part uses them by name.

Quick check

1. What goes in a header file?
2. What is an include guard for?
3. What does static do to a global variable?
My notes

Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.