Built with Tutify.io

    AIStudyLabs

    Setting Up Project Structure

    Setting Up Project Structure

    Introduction

    In this lesson, you’ll move from writing individual C files to organizing a complete, maintainable project. You’ll learn how to structure folders, name files clearly, use a Makefile for automated builds, track your work with version control, and document your project so that others (and future you) can understand and extend it easily.


    Designing a Folder Structure for a C Project

    A clear folder layout keeps growing projects manageable. For a small-to-medium C project, a common structure is:

    my_c_project/
    ├── src/           # All .c source files
    ├── include/       # All .h header files
    ├── build/         # Compiled object files, binaries (often auto-created)
    ├── tests/         # Test source files and data
    ├── docs/          # Documentation
    ├── Makefile       # Build automation
    └── README.md      # Project overview and usage
    

    Why Separate src and include?

    This separation makes it easy to:

    Example: Minimal Project Layout

    my_c_project/
    ├── src/
    │   ├── main.c
    │   ├── math_utils.c
    │   └── io_utils.c
    ├── include/
    │   ├── math_utils.h
    │   └── io_utils.h
    ├── Makefile
    └── README.md
    

    Each .c file has a corresponding header if it exposes functionality to other parts of the program.


    File Naming Conventions

    Consistent naming makes it easier to find and understand code.

    General Guidelines

    Examples:

    Avoid vague names like misc.c or temp.c in real projects; they accumulate unrelated code and become hard to maintain.


    Creating a Makefile for Automated Builds

    Manual compilation works for tiny programs, but it quickly becomes painful as files multiply. A Makefile automates compilation and links only what changed.

    Example Project Files

    Assume this structure:

    my_c_project/
    ├── src/
    │   ├── main.c
    │   ├── math_utils.c
    │   └── io_utils.c
    ├── include/
    │   ├── math_utils.h
    │   └── io_utils.h
    └── Makefile
    

    Sample Makefile

    # Simple Makefile for a small C project
    
    CC      = gcc
    CFLAGS  = -Wall -Wextra -std=c11 -Iinclude
    
    SRC_DIR = src
    BUILD_DIR = build
    
    SRCS    = $(SRC_DIR)/main.c \
              $(SRC_DIR)/math_utils.c \
              $(SRC_DIR)/io_utils.c
    
    OBJS    = $(SRCS:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
    TARGET  = $(BUILD_DIR)/my_c_project
    
    .PHONY: all clean
    
    all: $(TARGET)
    
    $(TARGET): $(OBJS)
    	@mkdir -p $(BUILD_DIR)
    	$(CC) $(CFLAGS) -o $@ $^
    
    $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
    	@mkdir -p $(BUILD_DIR)
    	$(CC) $(CFLAGS) -c $< -o $@
    
    clean:
    	rm -rf $(BUILD_DIR)
    

    Explanation and Output

    # Output (terminal commands and results)
    $ make
    # ...object files compiled into build/
    # ...executable created as build/my_c_project
    
    $ ./build/my_c_project
    # Program runs
    
    $ make clean
    # build directory removed
    

    You can extend this Makefile later to add tests, debug builds, or different targets.


    Using Version Control (Git) for Project Management

    Version control lets you track changes, experiment safely, and collaborate.

    Initializing a Git Repository

    From your project root (my_c_project):

    # Initialize repository and create first commit
    $ git init
    $ git add .
    $ git commit -m "Initial project structure with Makefile"
    

    Ignoring Build Artifacts

    You usually don’t want compiled files and build directories in your repository. Add a .gitignore file:

    # .gitignore
    build/
    *.o
    *.exe
    *.log
    

    Then:

    $ git status
    # Should show only relevant source, headers, docs, etc.
    

    Working with Branches (Conceptually)

    For new features or experiments, you typically create a branch:

    $ git checkout -b feature/new-math-functions
    # edit src/math_utils.c, include/math_utils.h, etc.
    $ git add src/math_utils.c include/math_utils.h
    $ git commit -m "Add new math functions"
    

    Branches help isolate work and keep the main branch stable.


    Documenting Project Structure and Components

    Good documentation explains what your project does and how it’s organized.

    Writing a Minimal README.md

    Create a README.md in the project root:

    # My C Project
    
    ## Overview
    A small C project demonstrating modular code structure, automated builds with Makefile,
    and basic utilities for input/output and math operations.
    
    ## Project Structure
    - `src/` – C source files (`main.c`, `math_utils.c`, `io_utils.c`)
    - `include/` – Header files declaring public interfaces
    - `build/` – Compiled object files and the final executable (created by `make`)
    - `Makefile` – Build rules for compiling the project
    
    ## Building and Running
    ```bash
    make          # build the project
    ./build/my_c_project   # run the executable
    make clean    # remove build artifacts
    

    Components

    
    This gives new developers (or future you) a quick orientation.
    
    ### Inline Documentation with Comments
    
    Use comments in your headers to explain the purpose of each module and function. Example `include/math_utils.h`:
    
    ```c
    #ifndef MATH_UTILS_H
    #define MATH_UTILS_H
    
    /* math_utils.h
     * Utility functions for common arithmetic operations
     */
    
    int add(int a, int b);
    int subtract(int a, int b);
    
    #endif
    

    This complements your external docs and helps tooling (and humans) understand the code.


    Small Practical Example: Using the Project Layout

    src/main.c

    #include <stdio.h>
    #include "math_utils.h"
    
    int main(void) {
        int x = 5;
        int y = 3;
    
        int sum = add(x, y);
        int diff = subtract(x, y);
    
        printf("%d + %d = %d\n", x, y, sum);
        printf("%d - %d = %d\n", x, y, diff);
    
        return 0;
    }
    

    include/math_utils.h

    #ifndef MATH_UTILS_H
    #define MATH_UTILS_H
    
    int add(int a, int b);
    int subtract(int a, int b);
    
    #endif
    

    src/math_utils.c

    #include "math_utils.h"
    
    int add(int a, int b) {
        return a + b;
    }
    
    int subtract(int a, int b) {
        return a - b;
    }
    

    Explanation and Output

    # Output (after running the built program)
    5 + 3 = 8
    5 - 3 = 2
    

    Summary / Key Takeaways

    In this lesson Setting Up Project Structure, you have learned:

    C Programming Fundamentals: From Zero to Confident C Coder — Project Development and Implementation

    Introduction to Programming and C

    Variables and Data Types

    Control Structures: Conditions and Loops

    Functions in C

    Arrays and Strings

    Working with Pointers

    File Handling in C

    Structures and Unions in C

    Project Development and Implementation

    Advanced C Concepts and Best Practices

    Tutorial Not Found