Menu
Coddy logo textTech

The 'Self' Pointer

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

In object-oriented languages like Python or Java, when you call object.method(), the language automatically passes the object itself to the method. In C, we must do this manually by passing a pointer to the struct as the first argument.

This pointer is conventionally named self (borrowed from Python) or this (from C++). It gives the function access to the struct's data so it can read or modify it:

typedef struct {
    int health;
} Player;

void player_take_damage(Player *self, int amount) {
    self->health -= amount;
}

The self pointer is what makes the function act like a method—it knows which player to modify. Without it, the function would have no way to access the specific struct instance. When calling this function, you pass the address of your struct:

Player hero = {100};
player_take_damage(&hero, 25);
// hero.health is now 75

Using a pointer (rather than passing the struct directly) is essential for modification. If you passed the struct by value, the function would receive a copy, and any changes would be lost when the function returns. The pointer ensures changes persist in the original struct.

challenge icon

Challenge

Easy

Let's build a Timer module that tracks elapsed seconds. You'll practice using the "self" pointer pattern to modify a struct's internal state through functions that act as methods.

You'll create three files:

  • timer.h: Declare a Timer struct with a single int seconds member. Also declare two functions: timer_tick (takes a pointer to Timer and adds a specified number of seconds) and timer_reset (takes a pointer to Timer and sets seconds back to zero). Use include guards with the symbol TIMER_H.
  • timer.c: Implement both functions. The timer_tick function should accept a Timer *self and an int amount, then add the amount to the timer's seconds. The timer_reset function should accept a Timer *self and set its seconds to zero.
  • main.c: Create a Timer, perform operations on it, and display the results.

You will receive two integer inputs: the initial seconds for your timer and the amount to add via tick.

In your main file:

  1. Initialize a Timer with the initial seconds value
  2. Call timer_tick to add the specified amount
  3. Print the current seconds
  4. Call timer_reset to reset the timer
  5. Print the seconds again (should be 0)

Print the results in this format:

After tick: {seconds}
After reset: {seconds}

For example, with an initial value of 30 and adding 15 seconds, the output would be:

After tick: 45
After reset: 0

Cheat sheet

In C, functions that operate on structs need explicit access to the struct instance through a pointer parameter, conventionally named self or this:

typedef struct {
    int health;
} Player;

void player_take_damage(Player *self, int amount) {
    self->health -= amount;
}

The self pointer allows the function to access and modify the struct's data. When calling such functions, pass the address of your struct:

Player hero = {100};
player_take_damage(&hero, 25);
// hero.health is now 75

Using a pointer is essential for modification—passing by value would create a copy, and changes would be lost when the function returns. The pointer ensures changes persist in the original struct.

Try it yourself

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

int main() {
    int initial_seconds, amount_to_add;
    scanf("%d", &initial_seconds);
    scanf("%d", &amount_to_add);
    
    // TODO: Create a Timer and initialize it with initial_seconds
    
    // TODO: Call timer_tick to add amount_to_add seconds
    
    // TODO: Print the current seconds in format: "After tick: {seconds}"
    
    // TODO: Call timer_reset to reset the timer
    
    // TODO: Print the seconds again in format: "After reset: {seconds}"
    
    return 0;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming