You call inc(n). The function clearly increments its argument. So why is n unchanged afterwards? This question from our C Programming Quiz App tests the single most important fact about C function calls: C passes everything by value — and a function that forgets this compiles cleanly, runs happily, and does nothing.
The Quiz Question
void inc(int x) { x++; }
int n = 5;
inc(n);
printf("%d", n);
What is printed by this code?
- 6
- 5
- Compile error
- Undefined behavior
The Correct Answer: 5
The parameter x is a brand-new local variable that receives a copy of n‘s value. x++ increments the copy to 6; the copy is destroyed when inc returns. The caller’s n was never touched. Verified on gcc 13.3 and Apple clang 21:
$ gcc -ansi -Wall -Wextra byvalue.c && ./a.out 5
Interestingly, clang sees through the futility at compile time:
$ clang -Wall -Wextra byvalue.c warning: parameter 'x' set but not used [-Wunused-but-set-parameter]
The compiler is telling you the function modifies something nobody will ever read. (gcc 13.3 stays silent here — one more reason to build with more than one compiler.)
Why Each Wrong Answer Is Wrong
Why not 6?
6 is the pass-by-reference reading — true in C++ with void inc(int &x), but C has no references. To actually increment the caller’s variable in C, you pass its address and dereference:
void inc(int *x) { (*x)++; }
int n = 5;
inc(&n);
printf("%d", n);
$ ./a.out 6
Note what’s still true: the pointer itself is passed by value — the function gets a copy of the address. But a copy of an address points at the same original object, and that’s the whole trick.
Why not a compile error?
Everything is well-formed: inc takes an int, gets an int, modifies its own local parameter (perfectly legal), and returns nothing. A pointless program is not an invalid program.
Why not undefined behavior?
There’s no UB anywhere — no overflow, no invalid access, no unsequenced modification. The program’s behavior is completely defined; it’s just defined to be useless.
Parameters Are Local Variables — the Rule Behind Everything
The C standard treats each parameter as a local variable initialized with the corresponding argument’s value. Everything about C calls follows from this one rule:
- Assigning to a parameter never affects the caller — whether it’s an
int, astruct, or a pointer. - To let a callee modify caller state, pass a pointer to it — the idiom behind
scanf(&x), and the swap function in this same quiz cluster. - Structs are copied wholesale (which can be expensive — another reason large structs travel by pointer).
- Arrays are the apparent exception: an array argument decays to a pointer to its first element, so the callee can modify the elements. But it’s not an exception really — the pointer was passed by value.
Frequently Asked Questions
Is C pass by value or pass by reference?
Strictly pass by value — every argument is copied into the parameter. C has no references. “Pass by reference” is simulated by passing a pointer by value and dereferencing it inside the function.
How do I make a C function modify its argument?
Pass the variable’s address: declare the parameter as a pointer (void inc(int *x)), call with &n, and modify through the dereference ((*x)++). That changes the caller’s variable to 6 in this example.
Why does inc(n) compile if it does nothing?
Modifying your own local variable (which a parameter is) is legal C. Clang’s -Wunused-but-set-parameter warning can flag the pattern, but no rule of the language forbids it.
Related Reading
- Swap Using Pointers in C – How Functions Modify Caller Variables
- Copying a Value Through a Pointer in C
- Pointers in C – Complete Guide
- C Aptitude Questions and Answers
Recommended Books
- The C Programming Language – Kernighan & Ritchie (India) | Amazon.com
- C Programming: A Modern Approach – K.N. King (India) | Amazon.com
This question is #52 in the C Programming Quiz App — 155 questions with explanations covering functions, pointers, memory, and more.
Download on Google Play →