Menu
Coddy logo textTech

Project Overview

Part of the Object Oriented Programming section of Coddy's C journey — lesson 44 of 61.

challenge icon

Challenge

Easy

Let's lay the foundation for the Shape Drawer project by creating the base Shape struct — an interface that defines what any shape can do through function pointers.

You'll create two files to set up this polymorphic system:

  • shape.h: Define the core interface here. First, create a forward declaration for the Shape struct. Then define two function pointer types:
    • DrawFunc — takes a const Shape* parameter and returns nothing
    • AreaFunc — takes a const Shape* parameter and returns a double
    Finally, define the Shape struct itself containing two function pointers: draw (of type DrawFunc) and area (of type AreaFunc). This struct acts purely as an interface — it holds no shape-specific data, only behavior.
  • main.c: Demonstrate that your interface works by creating a simple test shape. Implement two functions:
    • test_draw — prints Drawing test shape
    • test_area — returns 42.0
    Create a Shape instance, wire it to these test functions, then call both through the interface. Print the area result with one decimal place.

Your output should demonstrate that the function pointers work correctly:

Drawing test shape
Area: 42.0

Why the forward declaration? You might wonder why typedef struct Shape Shape; appears before the struct is fully defined. This is necessary because DrawFunc and AreaFunc reference const Shape* in their parameter types — but at that point in the file, the compiler hasn't seen the full struct definition yet. The forward declaration tells the compiler: "a struct named Shape exists," which is enough to use a pointer to it. The full definition follows later. This pattern is common in C whenever a struct needs to reference itself (directly or through function pointers).

The key insight here is that Shape doesn't know anything about circles or rectangles — it only knows that any shape must be able to draw itself and calculate its area. In the upcoming lessons, you'll create concrete shapes that embed this base struct and provide their own implementations. Remember to use include guards in your header file.

Try it yourself

#include <stdio.h>
#include "shape.h"

// TODO: Implement test_draw function
// - Takes a const Shape* parameter
// - Prints "Drawing test shape"
void test_draw(const Shape* shape) {
    // TODO: Print the required message
}

// TODO: Implement test_area function
// - Takes a const Shape* parameter
// - Returns 42.0
double test_area(const Shape* shape) {
    // TODO: Return the test area value
}

int main() {
    // TODO: Create a Shape instance
    
    // TODO: Wire the shape to test_draw and test_area functions
    
    // TODO: Call draw through the interface
    
    // TODO: Call area through the interface and print with one decimal place
    // Format: "Area: %.1f\n"
    
    return 0;
}

All lessons in Object Oriented Programming