Placement Prep

How to Return Multiple Values from a Function in C

C functions return one value by default. This guide covers four methods: pointers, structs, arrays, and malloc, with working code examples for placement test prep.

By FACE Prep Team 7 min read
c-programming functions pointers data-structures placement-prep

C functions return exactly one value by design, but four standard patterns let you pass back two, three, or more results without changing the function signature.

This comes up in placement coding tests and technical interviews at every tier of IT hiring. AMCAT, CoCubes, and HirePro all run C language sections where multi-value return is tested. Interviewers at service-tier companies ask you to write a function that returns both the minimum and maximum of two numbers. Product-company interviews ask you to choose between patterns and explain the tradeoff. Knowing all four, and when to reach for each, is the difference between a correct answer and a well-reasoned one.

Why C Functions Return One Value

The C language specification allows exactly one return type per function declaration. A return statement carries one expression. On most architectures, that value travels back to the caller through a single CPU register (on x86-64 Linux, the integer return convention uses rax). One register, one value, one type.

C was written in the early 1970s as a portable layer above assembly language for Unix. The single-register return convention mapped directly to what the underlying hardware does: call a function, get one register back. Higher-level languages built since then (Python, Go, Rust) add tuple or multi-value returns as syntactic sugar on top of the same underlying mechanism. Standard C has no such sugar.

What it does have are four clean workarounds. None of them violate the one-value constraint; they route extra outputs through a different channel instead. Each suits a different situation, and each appears in different types of placement questions.

Method 1: Pointer Output Parameters

Pointer output parameters are the most common multi-value pattern in production C code and placement tests. Instead of returning extra values, the function accepts pointer arguments pointing to the caller’s variables and writes through them.

#include <stdio.h>

void getMinMax(int a, int b, int *min, int *max) {
    *min = (a < b) ? a : b;
    *max = (a > b) ? a : b;
}

int main() {
    int x = 10, y = 25, lo, hi;
    getMinMax(x, y, &lo, &hi);
    printf("Min: %d, Max: %d\n", lo, hi);
    return 0;
}

Output: Min: 10, Max: 25

How it works:

  • &lo passes the memory address of the local variable lo into getMinMax.
  • Inside the function, *min = ... dereferences the pointer and writes to lo in the caller’s stack frame.
  • After the call returns, lo holds 10 and hi holds 25.

This is the same pattern the C standard library uses throughout. scanf takes a pointer argument for every value it reads. strtol takes a pointer to store the end position of the parsed string. fgets takes a buffer pointer and a size. If you have written scanf("%d", &n), you have already used output pointer parameters.

When to use: any time you need 2 to 4 values of possibly different types from a single function call. Works under C89, C99, and C11 with no additional library headers.

Method 2: Returning a Struct

A struct groups logically related fields into a single named type. A function that returns a struct passes all its fields back to the caller in one return statement, without any pointer manipulation.

#include <stdio.h>

typedef struct {
    int quotient;
    int remainder;
} DivResult;

DivResult divide(int a, int b) {
    DivResult r;
    r.quotient  = a / b;
    r.remainder = a % b;
    return r;
}

int main() {
    DivResult res = divide(10, 3);
    printf("Quotient: %d, Remainder: %d\n", res.quotient, res.remainder);
    return 0;
}

Output: Quotient: 3, Remainder: 1

How it works:

  • divide(10, 3) computes 10 / 3 = 3 (integer division) and 10 % 3 = 1.
  • The return r; statement copies the struct by value back to the caller.
  • The caller accesses the fields via .quotient and .remainder.

The struct makes the return type self-documenting. A function declared as returning DivResult tells the caller exactly what comes back, with named fields. Compare that to a function with two int * output parameters; the caller has to read each parameter name to know which is which.

Product-company interviewers at Zoho, Freshworks, and Thoughtworks often prefer the struct answer when they ask a design-oriented question. It signals that you think about API clarity, not just whether the code produces the right numbers.

When to use: values that belong together conceptually and benefit from named fields. The struct name and field names replace implicit index-based or positional conventions.

Method 3: Array via Pointer

When you need multiple values of the same type and the count is fixed at compile time, passing an array by pointer is idiomatic C. The caller allocates the array; the function fills it.

#include <stdio.h>

void squareAndCube(int n, int results[2]) {
    results[0] = n * n;
    results[1] = n * n * n;
}

int main() {
    int out[2];
    squareAndCube(4, out);
    printf("Square: %d, Cube: %d\n", out[0], out[1]);
    return 0;
}

Output: Square: 16, Cube: 64

How it works:

  • out is a two-element array on the caller’s stack.
  • When squareAndCube(4, out) is called, the array name out decays to a pointer to its first element.
  • results[0] = 4 * 4 = 16, results[1] = 4 * 4 * 4 = 64.
  • The function writes into the caller’s array directly; no copy on return.

When to use: homogeneous output where all values are the same type, and positional indexing is sufficient to distinguish them. Simpler than defining a struct when the values have no meaningful names. Placement examiners sometimes phrase this as “write a function that stores both the square and cube of a number in an output array.”

Method 4: Dynamic Memory Allocation

malloc from <stdlib.h> allocates memory on the heap at runtime. A function can allocate an array of any size, fill it, and return the base pointer. The caller uses the data and then calls free().

#include <stdio.h>
#include <stdlib.h>

int *getValues(int count) {
    int *arr = (int *)malloc(count * sizeof(int));
    if (arr == NULL) return NULL;
    arr[0] = 42;
    arr[1] = 99;
    return arr;
}

int main() {
    int *data = getValues(2);
    if (data != NULL) {
        printf("First: %d, Second: %d\n", data[0], data[1]);
        free(data);
    }
    return 0;
}

Output: First: 42, Second: 99

Three rules for using malloc to return values:

  • Check the return for NULL before using the pointer. A failed allocation returns NULL, and dereferencing it is undefined behaviour.
  • Call free() in the caller when you are done. Every malloc without a matching free is a memory leak.
  • Never return a pointer to a local (stack-allocated) variable. Once the function returns, that stack frame is gone and the pointer becomes dangling.

When to use: when the count of return values is not known until runtime, or the data set is large enough that heap allocation makes more sense than a stack array. For standard placement test questions asking to return two values, the malloc method is rarely expected unless the question explicitly mentions dynamic allocation.

Comparing the Four Methods

MethodReturn mechanismBest whenMemory
Pointer output parametersWrite via *ptr in caller’s frame2 to 4 values of possibly different typesStack
Struct returnCopy by value at returnValues form a logical unit with named fieldsStack
Array via pointerCaller allocates; function fillsMultiple values of the same type, fixed countStack
mallocHeap pointer returnedCount unknown at compile time; large data setHeap — needs free

For placement tests at TCS, Infosys, Wipro, and Capgemini, pointer output parameters cover the bulk of C multi-return questions. Struct return appears as a follow-up in face-to-face interviews. Array questions are framed around sequences or batch output. malloc questions are explicitly labelled and are uncommon at the aptitude-screening stage.

Placement Coding Round Context

Three question forms appear across AMCAT, CoCubes, and HirePro C sections:

  • Form 1: “Write a function that finds both the minimum and maximum of two integers.” The expected approach is pointer output parameters, two int * arguments.
  • Form 2: “Write a function that returns the quotient and remainder of integer division.” Pointer output parameters or struct return both work; the struct answer is stronger in a face-to-face interview.
  • Form 3: “Compute and store the square and cube of an integer in an output array.” The expected approach is array via pointer.

All three test the same understanding: C lacks tuple returns, and the programmer must route extra outputs through the parameter list or a return type that aggregates values. Practising the pointer output parameter pattern until it is automatic covers the first two; adding the struct pattern covers the third.

For additional C practice questions covering conditionals, loops, and array manipulation, the C coding questions practice set covers problems drawn from past service-tier placement rounds. The Pascal’s triangle program in C is a companion exercise testing two-dimensional array handling and nested loops.

One follow-up that appears in technical interviews after the aptitude round: “Why not use a global variable to return the second value?” The answer is re-entrancy. If two threads call the same function simultaneously, they overwrite each other’s global, producing a race condition. Output pointer parameters and struct returns are both re-entrant because each call operates on its own stack frame.

Pointer output parameters, struct returns, and array pointers are the idioms that LLMs now generate C code against. When an AI code tool produces void getMinMax(int a, int b, int *min, int *max), it is applying exactly the patterns above. The skill is knowing whether the pattern fits the problem and catching when the generated code misses a NULL check or skips the free(). TinkerLLM is an LLM playground built around that loop: generate, read critically, and fix. The entry tier is ₹299.

Primary sources

Frequently asked questions

Can a C function return two integers at once?

Not directly. C functions return one value. Use pointer parameters (pass two int* arguments and assign inside the function), a struct containing both integers, or a two-element array passed by pointer.

What is the difference between returning a struct and using output pointer parameters?

Returning a struct copies all fields back to the caller by value. Pointer parameters modify variables in the caller's stack directly. Structs are cleaner when values are logically related; pointer params are more idiomatic for unrelated outputs.

Is malloc safe for returning multiple values from a C function?

Safe if the caller calls free() on the pointer afterward. Forgetting free() causes a memory leak. For fixed small counts, a stack-allocated array or struct avoids the heap entirely.

Which method is most common in placement coding tests in India?

Pointer output parameters are the most tested pattern in AMCAT, CoCubes, and HirePro C language sections. Struct return comes up in technical interviews at product companies.

Why not use a global variable to return extra values from a C function?

Global variables break re-entrancy. Two concurrent calls to the same function overwrite each other's global state. Output pointer parameters and struct returns are both re-entrant and the standard approach.

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