Skip to Content
Course content

44: Declaring and Dereferencing Pointers

Click on the "Edit" button in the top corner of the screen to edit your slide content.

One of the most frustrating hurdles when you first hit pointers in C is the asterisk. It’s a bit of a linguistic prank by the language designers: the * symbol means one thing when you're declaring a variable and something entirely different when you're actually using it in your code. I've seen plenty of developers spend an entire afternoon staring at a bug simply because they confused these two contexts.

The Illusion of the Updated Score

Let's look at a common scenario. Imagine you're building a simple game and you have a function meant to increase a player's score when they pick up a coin. You might start with something like this:

void add_score(int score) {
    score = score + 10;
}

int main() {
    int playerScore = 0;
    add_score(playerScore);
    // You'd expect playerScore to be 10 here, but it's still 0.
    return 0;
}

If you're coming from a language with managed references, this feels broken. You passed the variable in, you changed it inside the function, so why didn't it change in main? The problem is that C is strictly pass-by-value. When you call add_score(playerScore), you aren't passing the actual score variable; you're passing a copy of the number 0. The function dutifully increments that copy to 10 and then immediately throws it away when the function returns. Your original playerScore remains untouched, oblivious to the coin pickup.

Pointing to the Source of Truth

To actually change that value, we need to stop passing the value and start passing the address of the value. This is where declaring a pointer comes in. By changing the function signature to accept an int *, we're telling C, "I don't want a copy of an integer; I want the memory address where an integer lives."

void add_score(int *score_ptr) {
    *score_ptr = *score_ptr + 10;
}

int main() {
    int playerScore = 0;
    // We use the '&' operator to send the address of the variable
    add_score(&playerScore); 
    // Now playerScore is 10.
    return 0;
}

Here is the distinction that trips everyone up: in the line int *score_ptr, the asterisk is part of the type. It's just telling the compiler that score_ptr is a pointer. But inside the function, when we write *score_ptr, we are dereferencing. We're saying, "Go to the address stored in this pointer and actually touch the value sitting there."

The Cost of Direct Memory Access

You might wonder why we don't just do this for everything. There's a trade-off here. When you pass by value, the data is safe. The add_score function in the first example couldn't possibly mess up the rest of your program because it was working on a local copy. Once you start passing pointers, you're handing out the keys to your memory. If you pass a pointer to a function and that function accidentally writes to the wrong offset or dereferences a NULL pointer, you won't get a neat error message—you'll get a Segmentation Fault and a crash.

I usually advise treating pointers like a power tool: incredibly efficient for modifying shared state and avoiding expensive copies of large data, but dangerous if you aren't explicit about who owns the memory and when it's being modified. The rule of thumb I use is simple: if the function needs to "reach back" and change the caller's variable, use a pointer. If it just needs the data to perform a calculation, stick to a value.




📋 Practical Task

Exercise: Implementing a Player Health Regeneration System

You are tasked with writing a health regeneration system for an RPG. Instead of returning a new health value, you must create a function that modifies the player's current health directly in memory.

Requirements:

  • Create a function called regenerate_health that takes two arguments: a pointer to an integer (the player's current health) and an integer (the amount to heal).
  • Inside the function, dereference the pointer to increase the health value.
  • Ensure the health does not exceed a maximum cap of 100. If the regeneration would put them over 100, set the health exactly to 100.
  • In your main function, declare a health variable starting at 85, call your regeneration function with a value of 20, and print the result to verify it is capped at 100.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.