Project Overview
Part of the Object Oriented Programming section of Coddy's C journey — lesson 44 of 61.
Challenge
EasyLet'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 theShapestruct. Then define two function pointer types:DrawFunc— takes aconst Shape*parameter and returns nothingAreaFunc— takes aconst Shape*parameter and returns adouble
Shapestruct itself containing two function pointers:draw(of typeDrawFunc) andarea(of typeAreaFunc). 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— printsDrawing test shapetest_area— returns42.0
Shapeinstance, 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.0Why 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
1Modular Programming Basics
Header FilesInclude GuardsSource FilesStatic FunctionsRecap: Modular Calculator4Encapsulation
Opaque Pointers ConceptDefining Opaque StructsGetters and SettersValidation in SettersRecap: Secret Box2Objects and Methods
Structs as ObjectsThe 'Self' PointerConst CorrectnessPointer vs ValueHelper MethodsRecap: Point Manager5Project: Simple Bank Account
Project SetupImplementation of Account3Object Lifecycle
Constructor PatternDestructor PatternStack InitializationDeep CopyRecap: String Wrapper6Inheritance via Composition
Struct EmbeddingThe First Member RuleAccessing Parent MembersUpcastingRecap: Shape Hierarchy9Project: Shape Drawer
Project OverviewCircle Implementation