The First Member Rule
Part of the Object Oriented Programming section of Coddy's C journey — lesson 29 of 61.
When you embed a struct as the first member of another struct, something powerful happens: the memory address of the outer struct is identical to the memory address of its first member. This is guaranteed by the C standard.
Consider our previous example:
typedef struct {
int id;
} Parent;
typedef struct {
Parent parent; // First member
int grade;
} Child;When you create a Child variable, the Parent member sits at the very beginning of the Child's memory. This means a pointer to Child points to the exact same address as a pointer to its Parent member.
Child c;
Child* child_ptr = &c;
Parent* parent_ptr = (Parent*)child_ptr; // Safe cast!Both pointers hold the same address. This allows you to pass a Child* to any function expecting a Parent*:
void print_id(Parent* p) {
printf("ID: %d\n", p->id);
}
// In main:
Child c;
c.parent.id = 42;
print_id((Parent*)&c); // Works perfectlyThis technique is the foundation of inheritance in C. A function written for the base type can operate on any derived type, as long as the base is embedded first. The cast is safe because the memory layouts align perfectly.
Challenge
EasyLet's explore the first member rule by building a simple animal hierarchy. You'll create a base Animal struct and a derived Dog struct, then demonstrate how a pointer to Dog can be safely cast to a pointer to Animal.
The key insight you'll apply: when Animal is the first member of Dog, both structs share the same starting memory address. This means you can pass a Dog* to any function expecting an Animal* by casting the pointer.
You'll organize your code across three files:
animal.h: Define both structs with include guards. YourAnimalstruct should have a single field:legs(an integer representing the number of legs). YourDogstruct should embedAnimalas its first member and add anamefield (a character array of 50 characters). Also declare a functionprint_animalthat takes anAnimal*parameter.animal.c: Implement theprint_animalfunction. This function works with the base type—it only knows aboutAnimaland prints how many legs the animal has.main.c: Create aDogvariable and populate its fields (both the embedded animal's legs and the dog's name). Then demonstrate the first member rule by casting yourDog*to anAnimal*and passing it toprint_animal. Also print the dog's name separately to show the complete picture.
You will receive two inputs: the dog's name (a string) and the number of legs (an integer).
Your output should look like this:
Dog: Buddy
Legs: 4Where Buddy is the dog's name and 4 is the number of legs. Print the dog's name first from main.c, then call print_animal with the cast pointer to display the legs.
This demonstrates how a function written for the base type (Animal) can seamlessly work with a derived type (Dog) through pointer casting—the foundation of inheritance in C.
Cheat sheet
When a struct is embedded as the first member of another struct, both structs share the same starting memory address. This is guaranteed by the C standard.
typedef struct {
int id;
} Parent;
typedef struct {
Parent parent; // First member
int grade;
} Child;A pointer to the outer struct can be safely cast to a pointer to its first member:
Child c;
Child* child_ptr = &c;
Parent* parent_ptr = (Parent*)child_ptr; // Safe cast - same addressThis allows passing a derived type pointer to functions expecting the base type:
void print_id(Parent* p) {
printf("ID: %d\n", p->id);
}
Child c;
c.parent.id = 42;
print_id((Parent*)&c); // Works because memory layouts alignThis technique is the foundation of inheritance in C, enabling functions written for base types to operate on derived types.
Try it yourself
#include <stdio.h>
#include <string.h>
#include "animal.h"
int main() {
// Read input
char name[50];
int legs;
scanf("%s", name);
scanf("%d", &legs);
// TODO: Create a Dog variable
// TODO: Set the dog's name using strcpy
// TODO: Set the number of legs (access through the embedded Animal)
// TODO: Print the dog's name in format: "Dog: <name>"
// TODO: Cast Dog* to Animal* and call print_animal
// This demonstrates the first member rule!
return 0;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
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 Hierarchy