Call by Value, Address and Reference: C and C++ Worked Examples
Learn what C actually copies during a function call, how pointers still change caller-owned data, and where C++ references differ. Every case is traced to its final value.
KnowledgeGate Team
Exam prep & CS education

Value, address and reference sound like parallel mechanisms. Yet a C output question can mix a copied integer, copied pointer and modified caller object. Track caller objects, callee copies, stored addresses and surviving values to distinguish the mechanisms. The central correction is simple: C passes every argument by value. “Call by address” means passing an address value to a pointer parameter; native references belong to C++. The GATE category is the broader preparation route.
Call by value, call by address and call by reference: the exact distinction
Start at 10: value passing copies it; address passing copies its address; C++ reference passing binds alias r.
label | language | parameter | call | what is copied or bound | caller result |
|---|---|---|---|---|---|
call by value | C |
|
| value |
|
call by address | C |
|
| address copied |
|
call by reference | C++ |
|
|
|
|
n = n + 7 makes local n = 17. *p = *p + 7 writes 17 into caller object; a reference writes via an alias. C has no native reference parameter syntax. p is passed by value.
What the call frames contain: trace 10 through all three forms
void add7_value(int n) {
n = n + 7;
}
void add7_address(int *p) {
*p = *p + 7;
}
/* C++ only */
void add7_reference(int& r) {
r = r + 7;
}Use independent callers:
int a = 10; add7_value(a); /* a is 10 */
int b = 10; add7_address(&b); /* b is 17 */
/* C++ */
int c = 10; add7_reference(c); /* c is 17 */For the value call, the caller has a = 10. The callee creates n = 10, updates it to 17, then removes it on return. Caller a remains 10.
For the address call, suppose b at 0x1000 stores 10. Local p at 0x2000 copies 0x1000. Dereferencing it stores 10 + 7 = 17 in b. These addresses are illustrative, not runtime predictions.
For C++, r is another label on the c object, not a second integer box. Assigning through r changes c to 17.

Swap worked example: why copied values fail and addresses succeed
Begin with caller variables x = 4 and y = 9. In swap_value(int a, int b), the parameters start as local copies (4, 9). Then temp = a = 4, a = b = 9, and b = temp = 4. The local pair becomes (9, 4), but those variables disappear on return. The caller remains (x, y) = (4, 9).
In swap_address(int *a, int *b), temp = *a = 4, *a = *b = 9, and *b = temp = 4. The caller therefore ends at (x, y) = (9, 4). The only semantic change is that the second function writes through copied pointer values to caller-owned objects. A C++ swap_reference(int& a, int& b) can use the same three assignments without *, called as swap_reference(x, y).
A reliable swap matters when tracing the transformations in Sorting Algorithms: Complexity and Comparison.
Always report caller variables after the function's local frame has been discarded.
Arrays are the classic C trap: elements can change while size does not
Consider this exact fragment:
void adjust(int a[], int n) {
a[1] = a[1] + 5;
n = n + 1;
}
int marks[3] = {10, 20, 30};
int count = 3;
adjust(marks, count);In a function parameter, int a[] is adjusted to int *a. The pointer value designating marks[0] is copied. Therefore a[1] designates the caller's second element: 20 + 5 = 25, producing {10, 25, 30}. Parameter n is a separate integer copy. Its local calculation is 3 + 1 = 4, but that copy disappears, so caller variable count remains 3.
The caller's array storage is not duplicated. Because the copied pointer still reaches that storage, the indexed write survives return. No pointer reaches count, so only the callee's n box receives 4.
Printing the three elements and count gives exactly 10 25 30 3. The C Programming course covers the surrounding arrays, pointers and function syntax.
Changing a pointee is not the same as changing the caller's pointer
Trace void redirect_local(int *p, int *target) { p = target; *p = 99; } with int x = 12, y = 40; int *q = &x; redirect_local(q, &y);. Parameter p copies q and points to x; target points to y. Assignment p = target redirects local p; *p = 99 changes y. The return state is x = 12, y = 99, q still pointing to x, and *q = 12.
Now use void redirect_caller(int **p, int *target) { *p = target; }. Reset to x = 12, y = 40, q = &x. Calling redirect_caller(&q, &y) makes p point to caller variable q, so *p = target stores &y there. Finally, q == &y and *q = 40.

Next, Binary Trees and Binary Search Trees shows the same pointer reasoning applied to linked nodes.
Aliasing and output questions: trace writes in statement order
Call void update(int *p, int *q) { *p = *p + 3; *q = *q * 2; } using int x = 5; update(&x, &x);. Both pointers designate one object. First, 5 + 3 = 8. The second statement reads 8 and computes 8 * 2 = 16. The final value is 16, not 13 or 10.
For a mixed drill, call void f(int *p, int q) { *p = *p + 2; q = q + 2; } with int a = 6, b = 9; f(&a, b);. The dereference makes a = 6 + 2 = 8. Local q = 9 + 2 = 11 disappears, while caller b = 9. The printout is 8 9.
Typical exam questions ask you to predict values, find aliases, repair a swap, distinguish p from *p, or choose a double pointer.
Common mistakes and a five-step method for value, pointer and reference call traces
mistake | correction | verify with concrete values |
|---|---|---|
separate C mechanism | C copies a pointer |
|
| first redirects; second writes |
|
omitting | pass an address |
|
| parameter becomes a pointer |
|
|
| pass element count |
C++ | references are C++ only |
|
Use five steps: draw caller objects; bind or copy each parameter; mark stored addresses; execute dereferences in order; discard the callee frame and report surviving caller state. This also exposes why update(&x, &x) finishes at 16.
Call by value, address and reference: the short version and next step
C copies every argument value. Copied integers isolate changes; copied pointers can modify pointees; changing a caller's pointer needs another indirection. C++ references are alias syntax, not C.
The checked results are 10, 17, 17 for the add-7 cases; (4, 9) versus (9, 4) for the swaps; {10, 25, 30} with count 3; and 16 for the aliased update. Draw caller state and trace each statement in order before checking an answer. For a broader structured next step, use GATE Guidance by Sanchit Sir.
Keep learning

Functions in C: Syntax, Parameters and Worked Examples
Learn how C declarations, calls, and definitions fit together. Compile two complete programs, follow their values, and trace composition and recursion.

Smart Pointers in C++: unique_ptr, shared_ptr and weak_ptr with Worked Examples
Learn who owns a C++ object, when it is destroyed, and how to choose among unique_ptr, shared_ptr, weak_ptr and a borrowed raw pointer.

Pointers in C: Addresses, Arrays and Functions with Worked Examples
Build a practical pointer model with runnable C programs for dereferencing, arrays, swapping, dynamic memory and common tracing questions.

Pointers and Arrays in C: Decay, Indexing and Worked Examples
Separate arrays from pointers with runnable traces covering indexing, one-past boundaries, function parameters, two-dimensional arrays and declaration traps.