Skip to Content
Course content

63: Passing Structs to Functions

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

If you've spent any time with higher-level languages like Java, Python, or C#, you've likely developed a habit of assuming that when you pass an "object" into a function, you're passing a reference to that object. You might assume that if you change a property of that object inside the function, the change sticks. In C, this is a dangerous assumption when it comes to structs.

Thinking Structs are Passed by Reference by Default

Let's look at a common mistake. Imagine we're building a simple RPG and we have a Player struct. You want a function that handles taking damage. It feels natural to write it like this:

typedef struct {
    char name[50];
    int health;
    int level;
} Player;

void takeDamage(Player p, int amount) {
    p.health -= amount;
    printf("Inside function: %s took %d damage. Health is now %d\n", p.name, amount, p.health);
}

int main() {
    Player hero = {"Aragorn", 100, 10};
    takeDamage(hero, 20);
    printf("Outside function: %s health is %d\n", hero.name, hero.health);
    return 0;
}

If you run this, you'll see something frustrating: the output says health is 80 inside the function, but it's still 100 outside. Why? Because in C, structs are passed by value. When you call takeDamage(hero, 20), C creates a bit-for-bit copy of the entire hero struct and hands that copy to the function. You aren't modifying Aragorn; you're modifying a temporary clone of Aragorn that gets destroyed the moment the function returns.

Updating State with Pointers and the Arrow Operator

To actually modify the original struct, you have to pass a pointer to it. This tells C, "Don't copy the whole data structure; just tell the function where the original lives in memory."

Once you pass a pointer, you can't use the dot (.) operator directly on the pointer because the pointer is just a memory address, not the struct itself. You could dereference the pointer first—(*p).health—but that's clunky and annoying to write. Instead, we use the arrow operator (->), which is essentially shorthand for "dereference this pointer and access this member."

void takeDamage(Player *p, int amount) {
    // p is now a pointer to the original Player struct
    p->health -= amount; 
    printf("Inside function: %s took %d damage. Health is now %d\n", p->name, amount, p->health);
}

int main() {
    Player hero = {"Aragorn", 100, 10};
    // Pass the address of hero using the & operator
    takeDamage(&hero, 20); 
    printf("Outside function: %s health is %d\n", hero.name, hero.health);
    return 0;
}

Now, the health is 80 in both places. We've modified the original memory.

The Hidden Cost of Pass-by-Value

Even if you don't need to modify the struct, you should still think twice before passing by value. If your struct only has two integers, copying it is cheap. But what if your struct contains a large array or dozens of fields? Every time you pass that struct by value, C has to copy every single byte of that data onto the stack. It's a silent performance killer.

I generally follow this rule of thumb: if the struct is larger than a few words, pass a const pointer to it. Using const Player *p tells the compiler (and other programmers) that the function needs to see the data, but it isn't allowed to change it. You get the speed of a pointer with the safety of a value copy.




📋 Practical Task

Exercise: RPG Character Stat Modifier

You are tasked with creating a "Level Up" system for a game. You need to implement a function that modifies a character's stats when they gain a level.

Requirements:

  • Define a struct named Character with the following fields: char name[30], int level, int strength, and int agility.
  • Create a function called levelUp that takes a pointer to a Character and an int representing the bonus points to be distributed.
  • Inside levelUp, you must:
    1. Increment the level by 1.
    2. Add half of the bonus points to strength.
    3. Add the other half of the bonus points to agility.
  • In your main function, initialize a Character, print their stats, call the levelUp function, and then print the stats again to prove the changes persisted.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.