Placement Prep

Functions in C and C++: What Placement Tests Actually Test

Declarations, definitions, pass by value, pass by reference: the function concepts that C and C++ placement OA rounds check repeatedly.

By FACE Prep Team 6 min read
c-programming cpp functions pass-by-value pass-by-reference placement-prep coding-aptitude

Every placement OA in C tests the same assumption: you know how functions declare, define, call, and pass arguments, and you can trace two nested calls without running the code.

This guide covers exactly those concepts, with the C versus C++ distinctions that trip students who learned one before the other.

What a Function in C Does

A function is a named, self-contained block of code that takes zero or more inputs, performs one computation, and returns a result. Write the logic once, call it from anywhere. That is the entire value proposition of functions in C.

Every C program contains at least one function: main(). The operating system calls main() to start the program, and the integer that main() returns signals success or failure to the shell (0 is success by convention).

Here is the simplest possible demonstration:

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

int main() {
    int result = add(10, 20);
    printf("Sum: %d\n", result);
    return 0;
}

add takes two integers, computes their sum, and returns it. main calls add, receives the return value, and prints it. Declaration, definition, call, return: the complete function model in twelve lines.

Declare, Define, Call

Understanding the difference between these three steps is the first thing OA tests probe.

Declaration

A function declaration (also called a prototype) tells the compiler the function’s name, return type, and parameter types before the definition appears in the source file. Parameter names are optional in a declaration; the compiler only needs the types.

int add(int, int);       /* types only — valid declaration */
int max(int a, int b);   /* names included — equally valid */

According to the C language functions reference at cppreference.com, a declaration establishes the function’s type: a return type paired with a parameter type list. Library functions like printf are declared in header files (stdio.h) and their definitions live in pre-compiled library files linked at build time. That is why you include stdio.h but never write the body of printf yourself.

Definition

The definition provides the actual body: the statements that execute when the function is called. A definition is also a declaration, so if the definition appears before any call site in the same translation unit, no separate prototype is needed.

int add(int a, int b) {   /* definition doubles as declaration */
    return a + b;
}

Call

A call transfers control to the function body, binds the supplied arguments to the formal parameters, runs the body, and returns the result to the call site.

int result = add(10, 20);   /* 10 binds to a, 20 binds to b */

When the function returns, the stack frame created for add is discarded and result holds the returned value.

Return Types: What Functions Can and Cannot Return

Every C function declares a return type. The return type must be specified explicitly in C99 and later (C89 allowed an implicit int; modern compilers reject that).

Common return types:

  • int, float, double, char — scalar values returned by copy
  • void — the function produces no return value
  • A pointer type (int *, struct Node *) — returns an address

Two things a C function cannot return directly:

  • Arrays. You can return a pointer to an array, but be cautious: returning a pointer to a local array is undefined behaviour because the local array ceases to exist when the function returns. Allocate on the heap with malloc if the caller needs the data to persist.
  • Another function. You can return a function pointer (int (*)(int, int) is a pointer to a function that takes two ints and returns int), but not the function itself.

Pass by Value vs. Pass by Reference

This section is the most tested area in C/C++ OA questions. Understand it at the level where you can predict output for nested calls without running the code.

Pass by Value

By default, C passes arguments by value: the function receives a copy of the argument. The caller’s original variable is not affected.

#include <stdio.h>

void triple(int x) {
    x = x * 3;   /* modifies the local copy only */
}

int main() {
    int n = 5;
    triple(n);
    printf("%d\n", n);   /* prints 5, not 15 */
    return 0;
}

The output is 5. Inside triple, x is a local copy of n. Assigning to x does not touch n in main. This is the most frequent source of wrong answers in predict-the-output questions: students assume the function modifies the original.

Pass by Reference in C (Using Pointers)

To let a function modify the caller’s variable, pass a pointer to that variable and dereference inside the function.

#include <stdio.h>

void triple(int *ptr) {
    *ptr = *ptr * 3;   /* dereference and modify through the pointer */
}

int main() {
    int n = 5;
    triple(&n);        /* pass the address of n */
    printf("%d\n", n); /* prints 15 */
    return 0;
}

&n is the memory address of n. Inside triple, *ptr dereferences that address and writes through it. The output is 15. The distinction from the pass-by-value example is the * dereference operator in the function body and the & address-of operator at the call site.

Pass by Reference in C++ (Using References)

C++ provides a cleaner syntax: reference parameters declared with &.

#include <iostream>

void triple(int &x) {
    x = x * 3;   /* x is an alias for the caller's variable */
}

int main() {
    int n = 5;
    triple(n);              /* no & needed at the call site */
    std::cout << n << "\n"; /* prints 15 */
    return 0;
}

The reference x inside triple is an alias for the caller’s n. No pointer syntax, no explicit dereference. The C++ language functions reference at cppreference.com covers reference parameters under parameter declarations and notes that references cannot be null, which makes them safer than raw pointers for this pattern.

What C++ Adds on Top of C Functions

C++ extends C’s function model in three ways that show up in placement tests.

Function Overloading

C++ allows multiple functions with the same name, as long as their parameter lists differ in type or count.

int add(int a, int b)         { return a + b; }
double add(double a, double b) { return a + b; }

The compiler selects the correct version at the call site based on argument types. C does not support overloading.

Default Parameters

C++ lets you assign default values to trailing parameters.

void printScore(int score, int bonus = 0) {
    std::cout << score + bonus << "\n";
}

printScore(80);     /* bonus defaults to 0, prints 80 */
printScore(80, 10); /* bonus = 10, prints 90 */

The void fun() Trap

This distinction is a genuine OA question pattern:

  • In C, void fun() means the parameter list is unspecified: any number of arguments are accepted at the call site without a compile error.
  • In C++, void fun() means no parameters: passing any argument is a compile error.
  • In both C and C++, void fun(void) explicitly means no parameters.

The portable, unambiguous style when a function takes no arguments is void fun(void).

Tracing Function Calls in OA Questions

Predict-the-output questions involving functions are solved the same way every time. The technique:

  • Step 1: list every function called, its parameters, and its return type.
  • Step 2: for each call site, identify the actual argument values being passed.
  • Step 3: determine whether each parameter is passed by value or by pointer/reference.
  • Step 4: trace the function body line by line, updating the correct variable (the local copy for pass-by-value; the original for pass-by-pointer/reference).
  • Step 5: note the return value and carry it back to the call site. Replace the function call expression with that value.
  • Step 6: for recursive calls, repeat from the innermost call outward.

A worked example using the triple pointer version:

  • n = 5 in main.
  • Call: triple(&n). Argument is the address of n.
  • Inside triple: ptr holds the address of n; *ptr = *ptr * 3 computes 5 times 3 = 15 and writes 15 to the address of n.
  • Return: triple returns nothing (void). Back in main, n is now 15.
  • printf prints 15.

That step-by-step trace solves the question without running the code.

Practice this technique on real OA patterns in C coding questions for aptitude rounds. Pascal’s Triangle in C is a good next exercise. The pattern-printing logic sits inside a function calling helper functions, so you get nested call tracing in a familiar problem. For a broader view of how OA tests combine coding with logical reasoning, coding and decoding question types in aptitude tests covers the question families that often appear alongside the C sections.

The function call model (fixed input, deterministic transform, predictable output) is the same mental model that scales from C OA tracing to reasoning about how LLM inference pipelines work. Every prompt is an input, every model layer is a function call, every token generated is a return value. TinkerLLM lets you run real LLM API calls for ₹299, and tracing what changes when you modify a prompt is the same skill you build when you trace what changes when you switch from pass-by-value to pass-by-pointer.

Primary sources

Frequently asked questions

Can a C function return multiple values?

Not directly. A C function has a single return type. The standard workarounds are returning a struct that holds multiple values, or using pointer parameters to write results back to the caller's variables.

What is the difference between void fun() in C and C++?

In C, void fun() means the parameter list is unspecified, so the compiler accepts any number of arguments. In C++, void fun() explicitly means no parameters, the same as void fun(void) in C. This distinction shows up in tricky predict-the-output questions.

Can I define a function after main() in C without a prototype?

No. Without a forward declaration above main(), the compiler sees the call before it knows the function's signature, which causes a compile error in C99 and later. Declare the function above main(), then define it below.

What happens if the declared return type does not match what the function actually returns?

The compiler warns or errors depending on the version. In C11 and C++11 and later, reaching the end of a non-void function without a return statement is undefined behaviour, meaning the returned value is unpredictable.

How does C++ function overloading work internally?

C++ uses name mangling: the compiler encodes parameter types into the function's internal symbol name, so int add(int,int) and float add(float,float) become different symbols at link time. C does not support overloading because it does not mangle names.

Build AI projects

A self-paced playground for building with LLMs.

TinkerLLM is FACE Prep's sister property. A guided environment for shipping real LLM applications, the kind of project that earns a paragraph on your resume, not a line.

Try TinkerLLM (₹299 launch)
Free AI Roadmap PDF