Laboratory 5

Laboratory 5 – Structures, Header Files and Multi-file Programs

In this laboratory, you will move from single-file programs to a small multi-file C project. The main goals are to introduce struct, typedef, header files, include guards, and compilation/linking of multiple source files.

struct typedef header files include guards multi-file programs math library

Laboratory Overview

What is new in this laboratory.

Until now, your programs were written mostly in a single .c file. In this laboratory, you will learn how to organize code into:

header file (.h)   → what exists
source file (.c)   → how it works
main program       → how we use it
This laboratory builds directly on functions and loops introduced in previous laboratories, but now the main focus is organization of code.
Main idea of this lab:
structures → declarations → header files → implementations → compilation → linking

In this laboratory, functions are used not only to organize code, but also to build a small reusable module for working with points and triangles.

Learning Outcomes

  • work in the correct laboratory directory on the AGH UNIX server,
  • define and use a structure representing a point in 2D space,
  • understand the role of typedef,
  • write and use a custom header file,
  • protect a header file with include guards,
  • distinguish between declarations and definitions,
  • split a program into multiple source files,
  • compile and link a multi-file C program,
  • use functions from math.h and link the math library with -lm.

Task 0 — Reminder and preparation

Before starting the exercises, log in to the AGH server and prepare the working directory.

Step 1 — Log in to the AGH UNIX server

ssh your_login@student.agh.edu.pl

Step 2 — Go to the course directory

cd ~/I2PL

Step 3 — Create the directory for Laboratory 5

mkdir lab5
cd lab5

Step 4 — General rules

  • Work only in ~/I2PL/lab5.
  • Keep all your programs in this directory.
  • Do not use global variables.
  • Keep the code readable and properly indented.
  • Compile with warnings enabled.
gcc -Wall program.c -o program
This laboratory continues the same workflow as before: work on student.agh.edu.pl, use nano, compile with -Wall, and run programs with ./program.

Task 1 — Define a point structure

Create your first structure representing a point in 2D space.

Step 1 — Create the file

nano ex17.c

Step 2 — Define a structure

Create a structure containing two coordinates:

struct POINT {
    float x;
    float y;
};

Step 3 — Create and test variables of this type

In main, declare a few points and print their coordinates.

struct POINT p1;
p1.x = 1.0f;
p1.y = 2.0f;

Step 4 — Compile and run

gcc -Wall ex17.c -o ex17
./ex17
A structure lets you group related values into one logical object. Here, the coordinates x and y belong together.

Task 2 — Introduce typedef

Simplify the structure type name using typedef.

Step 1 — Replace the previous form

Rewrite the structure definition so that you can use POINT directly:

typedef struct {
    float x;
    float y;
} POINT;

Step 2 — Compare both styles

Compare:

struct POINT p1;

with:

POINT p2;

Step 3 — Use the typedef version in your program

Update your declarations and test that everything still works.

typedef does not create a new kind of data by itself. It creates a convenient alias for an existing type.

Task 3 — Distance between two points

Write a function that calculates the distance between two points.

Step 1 — Create a function prototype

float distance(POINT a, POINT b);

Step 2 — Use the distance formula

For points (x1, y1) and (x2, y2), use:

d = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1))

Step 3 — Include the math header

#include <math.h>

Step 4 — Compile with the math library

gcc -Wall ex17.c -o ex17 -lm
Functions such as sqrt are declared in math.h and their implementations are provided by the math library.
This is one of the first times when compilation and linking must both be considered carefully.

Task 4 — Perimeter of a triangle

Use the distance function to calculate the perimeter of a triangle defined by three points.

Step 1 — Create a new function prototype

float perimeter(POINT a, POINT b, POINT c);

Step 2 — Use the distance function

The perimeter is the sum of the three side lengths:

AB + BC + AC

Step 3 — Test the function in main

Create three points and print the perimeter of the triangle they define.

Do not duplicate the distance formula three times unnecessarily. Use the function you already wrote.

Task 5 — Area of a triangle

Write a function that calculates the area of a triangle defined by three points.

Step 1 — Create a function prototype

float area(POINT a, POINT b, POINT c);

Step 2 — Use a coordinate formula

Calculate the area using coordinates directly:

area = |x1(y2-y3) + x2(y3-y1) + x3(y1-y2)| / 2

Step 3 — Use fabs if needed

Since the formula may produce a negative value depending on point order, use the absolute value.

fabs(...)

Step 4 — Test the function in main

Print the area for a sample triangle.

This formula avoids unnecessary geometric complications. It uses only the coordinates of the three points.

Task 6 — Create a header file

Move shared type definitions and function declarations into a custom header file.

Step 1 — Create the file

nano point.h

Step 2 — Add include guards

#ifndef POINT_H
#define POINT_H

/* content */

#endif

Step 3 — Put shared declarations inside

Move the following elements into point.h:

  • the typedef for POINT,
  • function declarations for distance, perimeter, and area.

Step 4 — Include the header in your source file

#include "point.h"
Include guards prevent the same header file from being processed multiple times in one translation unit.
Standard headers such as stdio.h and stdlib.h also protect themselves against repeated inclusion.

Task 7 — Declarations vs definitions

Understand what belongs in a header file and what belongs in a source file.

Step 1 — Put declarations in the header

In point.h, keep:

  • the type definition,
  • function prototypes.

Step 2 — Put function definitions in source files

The full function bodies should stay in .c files.

Step 3 — Remember the rule

header file (.h)   → shared declarations
source file (.c)   → implementations
A header file may contain more than just function declarations. It may also contain type definitions such as struct, typedef, enum, and preprocessor directives such as #define.

Task 8 — Split the program into multiple files

Create a small multi-file project using one header and several source files.

Step 1 — Create the files

nano distance.c
nano perimeter.c
nano area.c
nano ex18.c

Step 2 — Organize the code

  • point.h → typedef and declarations
  • distance.c → definition of distance
  • perimeter.c → definition of perimeter
  • area.c → definition of area
  • ex18.cmain and test code

Step 3 — Include your custom header

In each relevant source file, use:

#include "point.h"
Your source files should not duplicate the same type definitions and declarations. That is exactly why the header file exists.

Task 9 — Compile and link a multi-file program

Compile the source files separately, then link them into one executable program.

Step 1 — Compile each source file separately

gcc -Wall -c distance.c
gcc -Wall -c perimeter.c
gcc -Wall -c area.c
gcc -Wall -c ex18.c

Step 2 — Link the object files

gcc distance.o perimeter.o area.o ex18.o -o ex18 -lm

Step 3 — Run the final program

./ex18

Step 4 — Try the shorter one-line form

gcc -Wall distance.c perimeter.c area.c ex18.c -o ex18 -lm
The separate compilation form is longer, but it shows the compilation process more clearly.

Mini Theory — Custom headers and include paths

When you write:

#include "point.h"

the compiler searches for the header file in the current project and in include paths.

You can add an include path explicitly with:

gcc -Wall -I. ex18.c distance.c perimeter.c area.c -o ex18 -lm

-I directory adds a directory to the list of places where the compiler searches for header files.

In practice:
  • #include "point.h" is usually used for your own headers,
  • #include <stdio.h> is usually used for system headers.

Mini Theory — Libraries and linking options

Header files and libraries are not the same thing:

header file → declarations
library     → implementations used at link time

In this laboratory you use:

  • math.h for function declarations such as sqrt and fabs,
  • -lm to link the math library.
gcc -Wall ex18.c distance.c perimeter.c area.c -o ex18 -lm

-lname means: link with a library named libname. So -lm means: link with the math library.

-L directory adds a directory to the list of places where the linker searches for libraries. You usually need it only when the library is not in a standard system location.

What will be checked during the next laboratory

  • defining and using a structure type,
  • using typedef to simplify type names,
  • writing a custom header file with include guards,
  • distinguishing between declarations and definitions,
  • splitting a program into multiple source files,
  • compiling and linking a multi-file project,
  • using math.h and linking with -lm,
  • writing readable and properly indented code.