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

Updated 22 Sep 20266 min read

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

int n

add7_value(a)

value 10 copied

a = 10

call by address

C

int *p

add7_address(&a)

address copied

a = 17

call by reference

C++

int& r

add7_reference(a)

r bound as alias

a = 17

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

c
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:

c
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.

Three call frames comparing value, address and C++ reference passing, where only the last two change the caller.

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:

c
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.

Pointer diagrams contrasting redirect_local, which leaves q pointing at x, with redirect_caller, which repoints q to y.

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

a=10; b=17

p=target means *p=99

first redirects; second writes

y=99; q->x

omitting & at call

pass an address

add7_address(&b) gives b=17

int a[] copies array

parameter becomes a pointer

marks[1]=25; count=3

sizeof(a) gives array size

a is a pointer

pass element count

C++ int& is valid C

references are C++ only

c=17

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.