Functions — Deep Dive
0%
Advanced C  ·  IIT Level

Functions in C

From anatomy and call stack to scope, recursion, pass by value vs reference, function pointers, and 8 deep examples — everything a competitive exam expects you to know.

Anatomy of a Function
Return Types
Call Stack
Scope & Storage Class
Pass by Value vs Reference
Arrays in Functions
Recursion
Function Pointers
8 Programs

Contents

⚙️
Part A — Functions: Foundation to Internals
definition · anatomy · call stack · scope · parameter passing
§1

Why Functions Exist

A function is a named, self-contained block of code that performs one specific job. Without functions, every program would be one giant main() — no reuse, no organisation, no testing. Functions solve four fundamental problems:

  • Reusability — write once, call from anywhere, any number of times
  • Abstraction — caller doesn't need to know HOW the function works, only WHAT it returns
  • Modularity — break a 1000-line program into 20 focused functions, each easy to understand
  • Testability — each function can be tested independently; bugs are isolated

In C, main() itself is a function — it is called by the operating system when your program starts. Every C program is a collection of functions calling each other.

TypeDescriptionExamples
Library functionsPre-built — ready to useprintf, scanf, sqrt, strlen
User-defined functionsWritten by youadd(), isPrime(), factorial()
Recursive functionsCall themselvesfactorial(n), fibonacci(n)
Inline functionsCode expanded at call site (C99)inline int max(int a, int b)
anatomy
§2

Anatomy of a Function — 4 Parts

Every function has exactly four parts — return type, name, parameters, body

int
return type
 
add
function name
(
int a, int b
parameters
)
{ return a + b; }
body
RETURN TYPE
What type of value the function gives back. Use void if it gives nothing back.
FUNCTION NAME
Any valid identifier. Convention: use verbs — calculateArea, isPrime, sortArray
PARAMETERS
Inputs the function receives. Can be zero (empty parens). Must specify type for each.
BODY
The actual code between { }. Contains the logic and (usually) a return statement.
function_anatomy.c
C
#include <stdio.h>

/* Return type: int
   Name: add
   Parameters: two ints
   Body: returns their sum                          */
int add(int a, int b) {
    return a + b;
}

/* Return type: void (returns nothing)
   Name: printLine
   Parameters: none (empty)
   Body: prints dashes                              */
void printLine() {
    printf("------------------\n");
}

/* Return type: float
   Name: average
   Parameters: array + its size
   Body: computes and returns float average         */
float average(int arr[], int n) {
    int sum = 0;
    for (int i = 0; i < n; i++) sum += arr[i];
    return (float)sum / n;
}

int main() {
    int nums[] = {10, 20, 30, 40};

    printLine();
    printf("add(5, 8)       = %d\n", add(5, 8));
    printf("average(nums,4) = %.1f\n", average(nums, 4));
    printLine();
    return 0;
}
terminal
output
------------------
add(5, 8)       = 13
average(nums,4) = 25.0
------------------
return types
§3

Return Types — Every Possibility

Return TypeMeaningreturn statementUse case
voidReturns nothingreturn; (optional)print functions, setters
intReturns integerreturn n;calculations, status codes
float / doubleReturns decimalreturn 3.14;math functions
charReturns characterreturn 'A';char processing
int* / char*Returns pointerreturn ptr;string functions, dynamic memory
structReturns structreturn s;complex data objects
return_types.c
C
#include <stdio.h>

/* void — no return value */
void greet(char *name) {
    printf("Hello, %s!\n", name);
}

/* int — returns integer */
int square(int n) {
    return n * n;
}

/* char — returns character (grade) */
char getGrade(int marks) {
    if      (marks >= 90) return 'A';
    else if (marks >= 75) return 'B';
    else if (marks >= 55) return 'C';
    else                  return 'F';
}

/* int — returns 1 (true) or 0 (false) — boolean pattern */
int isEven(int n) {
    return (n % 2 == 0);
}

int main() {
    greet("Ananta");
    printf("square(7)    = %d\n", square(7));
    printf("grade(88)    = %c\n", getGrade(88));
    printf("isEven(4)    = %d\n", isEven(4));   /* 1 = true */
    printf("isEven(7)    = %d\n", isEven(7));   /* 0 = false */
    return 0;
}
terminal
output
Hello, Ananta!
square(7)    = 49
grade(88)    = B
isEven(4)    = 1
isEven(7)    = 0
prototype — declaration
§4

Function Prototype — Forward Declaration

C reads files top to bottom. If you call a function before it is defined, the compiler doesn't know its signature — what types it accepts, what type it returns. A prototype (also called a forward declaration) solves this by telling the compiler the function's signature before its full definition.

  • Prototype syntax: return_type function_name(param_types);
  • Parameter names are optional in prototype — types are enough
  • Without prototype: implicit declaration assumed (int) — dangerous in C
  • Header files (.h) are essentially collections of prototypes
prototype_demo.c
C
#include <stdio.h>

/* ── PROTOTYPES (forward declarations) ──────────────── */
int   factorial(int n);
int   isPrime(int n);
float power(float base, int exp);
/* names optional: float power(float, int); also valid */

/* ── main uses the functions ─────────────────────────── */
int main() {
    printf("5!      = %d\n",       factorial(5));
    printf("isPrime(17) = %d\n",  isPrime(17));
    printf("2^10    = %.0f\n",    power(2, 10));
    return 0;
}

/* ── definitions come AFTER main ────────────────────── */
int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

int isPrime(int n) {
    if (n <= 1) return 0;
    for (int i = 2; i * i <= n; i++)
        if (n % i == 0) return 0;
    return 1;
}

float power(float base, int exp) {
    float result = 1;
    for (int i = 0; i < exp; i++) result *= base;
    return result;
}
terminal
output
5!          = 120
isPrime(17) = 1
2^10        = 1024
IIT point — why loop till i*i <= n in isPrime? If n has a factor greater than √n, it must also have one smaller than √n. So checking only up to √n is sufficient. This reduces time from O(n) to O(√n) — for n=1000000, that is 1000 checks vs 1000000 checks.
call stack
§5

Call Stack and Stack Frames

Every time a function is called, C creates a stack frame in memory — a private block that holds the function's local variables, parameters, and the return address (where to continue after the function returns). These frames are stacked on top of each other. When a function returns, its frame is destroyed and all its local variables disappear.

This is why local variables do not persist between function calls — they live only as long as their stack frame exists.

Call stack during execution of: main → add → square (inner call)

↑ grows upward (top = currently executing)
FRAME 3 — square(7) — currently executing
local: n=7  |  return address: back to add()
↓ called from here
FRAME 2 — add(5, 8) — waiting for square to return
params: a=5, b=8  |  local: result=?  |  return address: back to main()
↓ called from here
FRAME 1 — main() — at the bottom, always first
local: x=13, nums[]={10,20}  |  return address: OS
call_stack_demo.c
C
#include <stdio.h>

void c_func() {
    int z = 300;
    printf("  c_func: z=%d  &z=%p\n", z, (void*)&z);
}

void b_func() {
    int y = 200;
    printf(" b_func: y=%d  &y=%p\n", y, (void*)&y);
    c_func();               /* c_func frame pushed ON TOP */
    printf(" b_func: back from c_func\n");
}

void a_func() {
    int x = 100;
    printf("a_func: x=%d  &x=%p\n", x, (void*)&x);
    b_func();               /* b_func frame pushed ON TOP */
    printf("a_func: back from b_func\n");
}

int main() {
    printf("=== Call Stack Demo ===\n");
    a_func();
    printf("main: back from a_func\n");
    return 0;
}
terminal — notice addresses decrease upward (stack grows down)
output
=== Call Stack Demo ===
a_func: x=100  &x=0x7fff...c0
 b_func: y=200  &y=0x7fff...a0
  c_func: z=300  &z=0x7fff...80
 b_func: back from c_func
a_func: back from b_func
main: back from a_func
IIT key insight — stack overflow: Each recursive call adds a new frame. With too many recursions (no base case, or n=100000), the stack runs out of space — program crashes with "stack overflow". Every recursive function MUST have a base case that stops the recursion.
scope and storage class
§6

Scope and Storage Class

Scope defines where a variable is visible (can be accessed). Lifetime defines how long a variable exists in memory. Every variable in C has both a scope and a lifetime determined by where and how it is declared.

Scope levels — inner scopes can access outer, but NOT vice versa

Global Scope — visible everywhere
int count = 0;   float PI = 3.14159;
Function Scope — visible only inside this function
int x = 10;   float sum = 0.0;
Block Scope — visible only inside this { }
int temp = x + 1;   (cannot see other function's x)
scope_storage.c
C
#include <stdio.h>

int globalCount = 0;    /* global — visible everywhere, persists forever */

void demoStatic() {
    static int calls = 0;  /* static local — persists between calls! */
    int  normal = 0;       /* automatic — re-created each call */
    calls++;
    normal++;
    globalCount++;
    printf("calls(static)=%d  normal(auto)=%d  global=%d\n",
           calls, normal, globalCount);
}

void demoRegister() {
    register int i;   /* hint to compiler: store in CPU register (fast) */
    for (i = 0; i < 5; i++) printf("%d ", i);
    printf("\n");
}

int main() {
    demoStatic();   /* calls=1 normal=1 global=1 */
    demoStatic();   /* calls=2 normal=1 global=2  ← static persists! */
    demoStatic();   /* calls=3 normal=1 global=3 */
    demoRegister();
    return 0;
}
terminal
output
calls(static)=1  normal(auto)=1  global=1
calls(static)=2  normal(auto)=1  global=2
calls(static)=3  normal(auto)=1  global=3
0 1 2 3 4
Storage ClassKeywordScopeLifetimeDefault value
Automatic(default inside fn)Local — within blockUntil block endsGarbage
Static localstatic inside fnLocal — within functionEntire program0
GlobalDeclared outside allWhole fileEntire program0
RegisterregisterLocal — within blockUntil block endsGarbage
ExternalexternMultiple filesEntire program0
parameter passing
§7

Pass by Value — A Copy is Sent

By default, C passes all arguments by value — the function receives a copy of the argument. Any changes made to the parameter inside the function do not affect the original variable in the caller. The two variables are completely separate.

pass_by_value.c
C
#include <stdio.h>

void tryToChange(int x) {
    printf("  Inside fn: x = %d (copy)\n", x);
    x = 999;    /* changes LOCAL COPY only — original untouched */
    printf("  Inside fn: x = %d (after change)\n", x);
}

/* Classic swap THAT DOESN'T WORK — pass by value */
void wrongSwap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    /* a and b are copies — originals in main unchanged! */
}

int main() {
    int num = 42;
    printf("Before: num = %d\n", num);
    tryToChange(num);
    printf("After:  num = %d  (UNCHANGED!)\n", num);

    int p = 10, q = 20;
    printf("\nBefore wrongSwap: p=%d q=%d\n", p, q);
    wrongSwap(p, q);
    printf("After  wrongSwap: p=%d q=%d (STILL SAME!)\n", p, q);
    return 0;
}
terminal
output
Before: num = 42
  Inside fn: x = 42 (copy)
  Inside fn: x = 999 (after change)
After:  num = 42  (UNCHANGED!)

Before wrongSwap: p=10 q=20
After  wrongSwap: p=10 q=20 (STILL SAME!)
Classic exam trap: The wrong swap compiles without error but produces wrong results silently. This is one of the most tested concepts in IIT questions — knowing when to use pointers (pass by reference) instead.
§8

Pass by Reference — Using Pointers

To actually modify the caller's variable, pass its address using the & operator. The function receives a pointer (the address), uses *ptr to dereference and reach the original value. Any change via *ptr directly modifies the original variable.

pass_by_reference.c
C
#include <stdio.h>

/* Correct swap — receives ADDRESSES of a and b */
void swap(int *a, int *b) {
    int temp = *a;   /* read value at address a */
    *a = *b;         /* write into location a */
    *b = temp;       /* write into location b */
}

/* Get both min and max in one function call */
void minMax(int arr[], int n, int *minOut, int *maxOut) {
    *minOut = arr[0];
    *maxOut = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] < *minOut) *minOut = arr[i];
        if (arr[i] > *maxOut) *maxOut = arr[i];
    }
}

int main() {
    int x = 10, y = 25;
    printf("Before swap: x=%d y=%d\n", x, y);
    swap(&x, &y);   /* pass ADDRESSES */
    printf("After  swap: x=%d y=%d\n", x, y);

    int arr[] = {40, 12, 75, 3, 58};
    int mn, mx;
    minMax(arr, 5, &mn, &mx);
    printf("Min=%d  Max=%d\n", mn, mx);
    return 0;
}
terminal
output
Before swap: x=10 y=25
After  swap: x=25 y=10
Min=3  Max=75
Why minMax works: A function can only return ONE value. But by receiving two output pointers, it can write two results back to the caller. This is the standard C pattern for multiple return values — scanf uses exactly this technique for every variable it reads.
§9

Arrays as Function Parameters

Arrays in C are always passed by reference — even without &. When you write void sort(int arr[], int n), C passes the address of the first element. Any changes to arr[i] inside the function modify the original array in the caller. There is no copy of the array made.

array_params.c
C
#include <stdio.h>

/* These three declarations are equivalent: */
/* void sort(int arr[], int n)              */
/* void sort(int arr[10], int n)            */
/* void sort(int *arr, int n)               */

void bubbleSort(int arr[], int n) {
    int i, j, temp;
    for (i = 0; i < n-1; i++)
        for (j = 0; j < n-i-1; j++)
            if (arr[j] > arr[j+1]) {
                temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp;
            }
}   /* original array IS sorted — not a copy */

void printArr(int arr[], int n) {
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("\n");
}

/* 2D array parameter — MUST specify column count */
void printMatrix(int m[][3], int rows) {
    for (int i=0;i<rows;i++) {
        for(int j=0;j<3;j++) printf("%4d",m[i][j]);
        printf("\n");
    }
}

int main() {
    int arr[] = {64, 25, 12, 92, 43};
    printf("Before: "); printArr(arr, 5);
    bubbleSort(arr, 5);
    printf("After:  "); printArr(arr, 5);

    int mat[2][3] = {{1,2,3},{4,5,6}};
    printMatrix(mat, 2);
    return 0;
}
terminal
output
Before: 64 25 12 92 43
After:  12 25 43 64 92
   1   2   3
   4   5   6
Key rule: For 2D array parameters, the first dimension (rows) can be omitted or left blank — but the second dimension (columns) MUST always be specified. This is the same reason as in declaration: C needs column count to compute row offsets.
🔁
Part B — Recursion & Advanced Topics
recursion · function pointers · 8 programs
§10

Recursion — Deep Understanding

Recursion is when a function calls itself. Every recursive solution must have:

  1. Base case — the condition that stops the recursion. Without it: infinite recursion → stack overflow → crash
  2. Recursive case — the function calling itself with a smaller version of the problem
  3. Progress toward base case — each recursive call must get closer to the base case, never further
recursion_deep.c
C
#include <stdio.h>

/* ── Factorial: n! = n × (n-1)! ─────────────────────── */
int factorial(int n) {
    if (n <= 1) return 1;              /* base case */
    return n * factorial(n - 1);       /* recursive case */
}
/* Trace for factorial(4):
   factorial(4) = 4 * factorial(3)
   factorial(3) = 3 * factorial(2)
   factorial(2) = 2 * factorial(1)
   factorial(1) = 1  ← BASE CASE
   unwind: 1 → 2 → 6 → 24               */

/* ── Fibonacci: fib(n) = fib(n-1) + fib(n-2) ──────── */
int fib(int n) {
    if (n <= 0) return 0;
    if (n == 1) return 1;             /* two base cases */
    return fib(n-1) + fib(n-2);       /* double recursion */
}

/* ── Power: base^exp using recursion ───────────────── */
double power(double base, int exp) {
    if (exp == 0) return 1;           /* anything^0 = 1 */
    if (exp < 0)  return 1.0 / power(base, -exp);
    if (exp % 2 == 0)               /* FAST power: O(log n) */
        return power(base * base, exp / 2);
    return base * power(base, exp - 1);
}

/* ── Sum of digits recursively ──────────────────────── */
int digitSum(int n) {
    if (n == 0) return 0;
    return (n % 10) + digitSum(n / 10);
}

int main() {
    printf("factorial(6)   = %d\n",  factorial(6));
    printf("fib(10)        = %d\n",  fib(10));
    printf("power(2,10)    = %.0f\n", power(2,10));
    printf("digitSum(9875) = %d\n",  digitSum(9875));

    printf("\nFibonacci series: ");
    for (int i = 0; i < 10; i++) printf("%d ", fib(i));
    return 0;
}
terminal
output
factorial(6)   = 720
fib(10)        = 55
power(2,10)    = 1024
digitSum(9875) = 29

Fibonacci series: 0 1 1 2 3 5 8 13 21 34
IIT complexity comparison — recursive Fibonacci:
Naive recursive fib(n) has O(2ⁿ) time — fib(40) makes ~300 million calls!
Iterative fib(n) has O(n) time — always prefer iterative for Fibonacci.
Fast power using divide-and-conquer has O(log n) — 2^1000 needs only 10 calls.
§11

Function Pointers

Functions in C are stored in memory like variables. A function pointer stores the address of a function, allowing you to call a function through the pointer or pass a function as an argument to another function. This is the foundation of callbacks, jump tables, and plugin architectures.

function_pointers.c
C
#include <stdio.h>

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }

/* A function that TAKES a function pointer as argument */
void apply(int x, int y, int (*op)(int,int), char *name) {
    printf("%s(%d, %d) = %d\n", name, x, y, op(x, y));
}

int main() {
    /* Declare a function pointer: int (*fp)(int, int) */
    int (*fp)(int, int);

    fp = add;               /* point to add function */
    printf("Direct call: %d\n", fp(10, 5));

    fp = sub;               /* now point to sub */
    printf("Direct call: %d\n", fp(10, 5));

    /* Pass function as argument — callback pattern */
    apply(10, 5, add, "add");
    apply(10, 5, sub, "sub");
    apply(10, 5, mul, "mul");

    /* Array of function pointers — dispatch table */
    int (*ops[3])(int,int) = {add, sub, mul};
    char *opName[] = {"+", "-", "*"};

    printf("\nDispatch table:\n");
    for (int i = 0; i < 3; i++)
        printf("10 %s 5 = %d\n", opName[i], ops[i](10, 5));

    return 0;
}
terminal
output
Direct call: 15
Direct call: 5
add(10, 5) = 15
sub(10, 5) = 5
mul(10, 5) = 50

Dispatch table:
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
💡
Part C — 8 Deep Programs
each example demonstrates a different function technique
E1

GCD and LCM Using Euclid's Algorithm

gcd_lcm.c
C
#include <stdio.h>

/* Euclid's algorithm: gcd(a,b) = gcd(b, a%b) */
int gcd(int a, int b) {
    if (b == 0) return a;        /* base case */
    return gcd(b, a % b);         /* a%b gets smaller every call */
}

int lcm(int a, int b) {
    return (a / gcd(a, b)) * b;   /* avoid overflow: divide first */
}

int main() {
    int pairs[][2] = {{48,18},{100,75},{17,13},{0,5}};
    printf("%-8s %-8s %-8s %-8s\n","a","b","GCD","LCM");
    printf("--------------------------------\n");
    for (int i = 0; i < 4; i++) {
        int a=pairs[i][0], b=pairs[i][1];
        printf("%-8d %-8d %-8d %d\n",a,b,gcd(a,b),lcm(a,b));
    }
}
terminal
output
a        b        GCD      LCM
--------------------------------
48       18       6        144
100      75       25       300
17       13       1        221
0        5        5        0
Why Euclid works: gcd(48,18) → gcd(18,12) → gcd(12,6) → gcd(6,0) → 6. Each step: the larger number is replaced by the remainder. The remainder always shrinks, guaranteeing termination.
E2

Tower of Hanoi — Classic Recursion

Move n disks from peg A to peg C using peg B as auxiliary. Rule: never place a larger disk on a smaller one. The elegant recursive insight: to move n disks, move n-1 to auxiliary, move disk n to target, then move n-1 from auxiliary to target.

tower_hanoi.c
C
#include <stdio.h>

int moveCount = 0;

void hanoi(int n, char from, char to, char aux) {
    if (n == 0) return;            /* base case — nothing to move */

    /* Step 1: move top n-1 disks from → aux */
    hanoi(n-1, from, aux, to);

    /* Step 2: move disk n from → to */
    printf("Move disk %d: %c → %c\n", n, from, to);
    moveCount++;

    /* Step 3: move n-1 disks from aux → to */
    hanoi(n-1, aux, to, from);
}

int main() {
    int n = 3;
    printf("Tower of Hanoi (%d disks):\n", n);
    printf("------------------------------\n");
    hanoi(n, 'A', 'C', 'B');
    printf("Total moves: %d  (= 2^%d - 1)\n", moveCount, n);
}
terminal
output
Tower of Hanoi (3 disks):
------------------------------
Move disk 1: A → C
Move disk 2: A → B
Move disk 1: C → B
Move disk 3: A → C
Move disk 1: B → A
Move disk 2: B → C
Move disk 1: A → C
Total moves: 7  (= 2^3 - 1)
E3

Binary Search — Recursive & Iterative

binary_search.c
C
#include <stdio.h>

/* Recursive binary search */
int bsearchRec(int arr[], int low, int high, int key) {
    if (low > high) return -1;         /* not found */
    int mid = low + (high - low) / 2;  /* avoids int overflow */
    if      (arr[mid] == key) return mid;
    else if (arr[mid]  < key) return bsearchRec(arr, mid+1, high, key);
    else                      return bsearchRec(arr, low, mid-1, key);
}

/* Iterative binary search */
int bsearchIter(int arr[], int n, int key) {
    int low = 0, high = n - 1;
    while (low <= high) {
        int mid = low + (high - low) / 2;
        if      (arr[mid] == key) return mid;
        else if (arr[mid]  < key) low  = mid + 1;
        else                      high = mid - 1;
    }
    return -1;
}

int main() {
    int arr[] = {2,5,8,12,16,23,38,56,72,91};
    int n = 10;
    int tests[] = {23, 56, 1, 100};

    printf("Array: 2 5 8 12 16 23 38 56 72 91\n\n");
    for (int i = 0; i < 4; i++) {
        int k = tests[i];
        int r = bsearchRec(arr, 0, n-1, k);
        printf("Search %3d: index=%2d  (%s)\n",
               k, r, r==-1?"NOT FOUND":"FOUND");
    }
}
terminal
output
Array: 2 5 8 12 16 23 38 56 72 91

Search  23: index= 5  (FOUND)
Search  56: index= 7  (FOUND)
Search   1: index=-1  (NOT FOUND)
Search 100: index=-1  (NOT FOUND)
Why mid = low + (high-low)/2 instead of (low+high)/2? When low and high are both large integers (near INT_MAX), their sum overflows. The safer formula avoids this: if low=2000000000 and high=2000000001, (low+high) would overflow but low+(high-low)/2 = 2000000000 + 0 is fine.
E4

String Utilities — Custom String Library

string_utils.c
C
#include <stdio.h>
#include <ctype.h>

/* Count length without strlen */
int myLen(char *s){
    int i=0; while(s[i]) i++; return i;
}

/* Reverse string in-place */
void myReverse(char *s) {
    int l=0, r=myLen(s)-1;
    while(l<r){ char t=s[l];s[l++]=s[r];s[r--]=t; }
}

/* Check palindrome */
int isPalin(char *s) {
    int l=0, r=myLen(s)-1;
    while(l<r) if(s[l++]!=s[r--]) return 0;
    return 1;
}

/* Convert to title case */
void titleCase(char *s) {
    int newWord = 1;
    for(int i=0;s[i];i++){
        if(s[i]==' ')      newWord=1;
        else if(newWord) { s[i]=toupper(s[i]); newWord=0; }
        else               s[i]=tolower(s[i]);
    }
}

/* Count a specific character */
int countChar(char *s, char c) {
    int cnt=0;
    for(int i=0;s[i];i++) if(s[i]==c) cnt++;
    return cnt;
}

int main() {
    char a[] = "racecar";
    char b[] = "hello world";
    char c[] = "hello ananta";

    printf("len('%s') = %d\n", a, myLen(a));
    printf("isPalin('%s') = %d\n", a, isPalin(a));
    printf("isPalin('%s') = %d\n", b, isPalin(b));
    myReverse(b);
    printf("reverse: %s\n", b);
    titleCase(c);
    printf("titleCase: %s\n", c);
    printf("countChar('racecar','a') = %d\n", countChar(a, 'a'));
}
terminal
output
len('racecar') = 7
isPalin('racecar') = 1
isPalin('hello world') = 0
reverse: dlrow olleh
titleCase: Hello Ananta
countChar('racecar','a') = 3
iit quiz
Q

IIT-Level Quiz — 6 Questions

Question 1 of 6

What is the output? void f(int x){x=99;} int main(){int a=5; f(a); printf("%d",a);}

Question 2 of 6

A static local variable is initialised to 0 automatically. It retains its value between function calls. A normal local variable does NOT. Why?

Question 3 of 6

How many times is factorial(0) called when computing factorial(4)?

Question 4 of 6

A function needs to return two values — the sum and product of two numbers. What is the correct C approach?

Question 5 of 6

Why is iterative Fibonacci O(n) but recursive Fibonacci O(2ⁿ)?

Question 6 of 6

Arrays are always passed by reference in C — even without &. Why?

Mastery Checklist

  • I know the 4 parts of every function: return type, name, parameters, body
  • I can write functions with void, int, float, char, and pointer return types
  • I understand prototypes and when they are required
  • I can explain call stack — each function call creates a stack frame
  • I understand scope: local, global, block — and that inner can see outer but not vice versa
  • I know the 4 storage classes: auto, static, register, extern
  • I know static local variables persist between function calls (data segment, not stack)
  • I understand pass by value — function gets a COPY, originals unchanged
  • I can implement correct swap using pointers (pass by reference)
  • I know arrays are always passed by reference (array name = pointer to first element)
  • I can write recursive functions with correct base case and recursive case
  • I know recursive Fibonacci is O(2ⁿ) and iterative is O(n)
  • I can declare and use function pointers including arrays of function pointers
  • I completed all 6 quiz questions