I still remember the day I introduced swapping or call by to a fresh batch of students.
It was a sultry July afternoon, and the fan in our old lab was making more noise than sense. We had just finished a lesson on functions, and everyone was feeling like they were finally “getting” C. That’s when I casually asked:
“Okay folks, let’s write a function to swap two numbers.”
A few hands shot up confidently.
An ambitious student let’s call him Arjun wrote this with a grin:
void swap(int x, int y) {
int temp = x;
x = y;
y = temp;
}
In main():
int a = 10, b = 20;
swap(a, b);
printf(“After swap: a = %d, b = %d”, a, b);
He ran it. Output?
After swap: a = 10, b = 20
Arjun looked at me with that classic, innocent betrayal you only see in C programming labs.
“Sir, I swapped it… why didn’t it swap?”
The First Hard Truth: C Uses Call by Value
So we paused everything, and I drew it out on the board. Two boxes: one for a, one for b each with their own memory locations. I explained: “When you call swap(a, b), you’re not handing over the actual variables. You’re handing over copies of their values. It’s like writing instructions on a piece of paper and giving a photocopy to someone else. They can scribble all over it, but the original remains untouched.” Students stared. I saw it hadn’t sunk in. So I pulled out my favorite metaphor.

The Pen Drive Metaphor
Imagine you have a pen drive with a file called data.txt. You give your friend a printout of the file and say: “Edit this.”
They can write on it, burn it, tear it but your actual data.txt file is unchanged. That’s call by value.
Now imagine you give them the actual pen drive. Whatever they do affects the real file. That’s call by reference.
“Ahhhh,” Arjun said.
Another student added, “So by default, C only gives the photocopy.”
Exactly.
Call by Value: What’s Really Happening?
Let’s say you write:
void swap(int x, int y) {
int temp = x;
x = y;
y = temp;
}
And call it like this:
int a = 10, b = 20;
swap(a, b);
What happens under the hood is:
- a’s value (10) is copied into x.
- b’s value (20) is copied into y.
Now, inside the swap() function, x and y are local variables. Swapping happens between them but a and b in main() are unaffected.
In C, the called function only sees copies, not the originals. That’s the crux of call by value.
The Student Mistake Hall of Fame
Let’s talk about the top mistakes my students make (and maybe you too):
- Assuming variable names matter.
Some try using the same names in the called function (a, b) thinking it will affect the originals. Nope. Names mean nothing. It’s about memory.
- Expecting permanent changes without pointers.
They modify values in a function, print correct results inside the function, then panic when the main() still shows old values.
- Trying to return multiple values.
C doesn’t support returning multiple values directly from a function. You need to pass addresses or use structures.
That brings us to…
Enter the Hero: Call by Reference Using Pointers
“Okay sir, so how can we swap two numbers using a function?”
Now we bring out the big guns: pointers.
Let’s look at a working version:
void swap(int *x, int *y) {
int temp = *x;
*x = *y;
*y = temp;
}
And call it like this:
int a = 10, b = 20;
swap(&a, &b);
printf(“After swap: a = %d, b = %d”, a, b);
This time, it prints: After swap: a = 20, b = 10
Magic? Nope just address level manipulation.
Let’s walk through it.
A Story from the Heap
I once asked my students to imagine two homes: House A and House B. I give you their addresses not just a photo of the residents.
You walk into House A, pick up their couch, and replace it with one from House B. Now when I go to House A, the couch has changed.
That’s what happens when you pass addresses using &a and &b.
Inside the function, x and y are pointers, holding the addresses of a and b. So *x means “value at address x”. This is how we get direct access to the original variables.
Let’s Get Visual (Without Drawing on Your Wall)
int a = 10; // memory address 1000
int b = 20; // memory address 2000
swap(&a, &b); // pass 1000 and 2000 to the function
In the function:
- x = 1000, y = 2000
- *x is 10, *y is 20
- Swap the values at these locations
Now, a and b in main() are changed because you directly changed what’s inside those addresses.
Why This Matters More Than You Think
Understanding call by reference isn’t just about swapping. It unlocks the door to:
- Modifying arrays inside functions
- Managing dynamic memory
- Writing efficient, real world C programs
- Understanding how libraries like scanf() work (hint: it takes addresses too)
scanf(“%d”, &x); // Notice the & It’s not a coincidence.
A Class Moment I’ll Never Forget
Once during a revision session, I asked: “What’s the difference between these two function calls?”
swap(a, b); //doesn’t work
swap(&a, &b); //works
A quiet student in the back raised his hand and said, “First one gives instructions. Second one gives control.”
He nailed it.
One Last Word of Caution
With great power comes great responsibility. Pointers can let you control the universe or crash it.
I’ve had students dereference NULL, point to freed memory, and even overwrite unrelated parts of memory (undefined behavior, the Voldemort of C).
So while call by reference is powerful, always know what you’re pointing to.
Check pointers before dereferencing. Use them only when you need to.
Why does C use call by value by default?
Because it’s simpler and safer. You get a copy, so the original stays untouched unless you explicitly pass a pointer.
Can we simulate call by reference without pointers?
Not directly. You’d have to return modified values or use structures but pointers are the idiomatic C way.
What happens if I forget to use & while calling the function?
The function receives a copy, not the address. Your changes won’t affect the original variables.
Can I use the same variable names in the function and main()?
Yes. C uses separate memory for local variables, so naming doesn’t cause conflicts.
Why do we use *x and not just x in the swap function?
Because x is a pointer holding an address. To access the actual value at that address, you use *x.