Unit 4: Functions
A function is a self-contained block of code that performs one task and can be called repeatedly, letting a large program be split into smaller, testable, reusable units. C programs are built from functions; execution always begins in main(), which calls other functions in turn.
- Modularity: Each function isolates one job, so faults are localised and code is reused instead of duplicated.
- The three parts: Every function needs a declaration (prototype), a definition (body), and one or more calls.
- Prototype: A statement of the form
returnType name(paramTypes);placed before use, telling the compiler the signature so it can check arguments. - Return type: The type of the value sent back with
return;voidmeans no value is returned. - Parameters vs arguments: Parameters are the variables in the definition; arguments are the actual values supplied at the call.
II. Function Definition — the body that does the work
A. Structure and syntax
The definition supplies the actual statements executed when the function is called.
- General form: header plus body.
CreturnType functionName(parameterList) { /* declarations and statements */ return value; /* optional */ } - Header components:
returnTypefixes whatreturnsends back;functionNameis the identifier used in calls;parameterListlists typed formal parameters, e.g.int add(int a, int b). returnstatement: Ends the function and hands one value to the caller;return a + b;both computes and exits. Avoidfunction may use a barereturn;or none.- Empty parameter list:
int getValue(void)states explicitly that no arguments are taken.
B. Worked example
int square(int n) { /* definition */
return n * n;
}
int main(void) {
int r = square(5); /* call, r becomes 25 */
printf("%d", r);
return 0;
}- Flow: control jumps to
squarewithn = 5, computes25, returns it to the assignment, then resumesmain.
III. Predefined Functions and User Defined Functions
Functions come from two sources: ready-made ones supplied by C, and ones the programmer writes.
A. Predefined functions
Functions already written, compiled and shipped inside the standard library.
- Definition: Also called built-in or library functions; you call them but never write their bodies.
- Header requirement: Their prototypes live in headers included with
#include, e.g.printfandscanfneed<stdio.h>,sqrtneeds<math.h>. - Examples:
sqrt(16.0)returns4.0;strlen("cat")returns3;pow(2,3)returns8.0. - Advantage: Tested, optimised code that saves effort and guarantees correctness for common tasks.
B. User defined functions
Functions the programmer creates for tasks the library does not cover.
- Definition: Written, named and defined by the developer, e.g. a
computeGrade()for a specific marking rule. - Why: Encapsulate application-specific logic, reduce repetition, and make the program readable.
- Steps: declare prototype → define body → call. Missing any step causes a compile or link error.
- Contrast with predefined:
- Predefined: source hidden, behaviour fixed by the standard, available everywhere the header is included.
- User defined: source visible and editable, behaviour chosen by the programmer, scoped to the program that defines it.
IV. Scope Rules — Local and Global Scope
Scope is the region of a program where a declared name is visible and usable; C decides it by where the declaration sits.
A. Local scope
A name declared inside a block is visible only within that block.
- Definition: Variables declared inside a function or
{}block are local; they exist only while the block runs. - Lifetime: Created on entry, destroyed on exit (automatic storage); a fresh copy each call.
- Isolation: Two functions may each declare
int i;with no clash, because eachiis separate. - Example: in
void f(){ int x = 5; },xcannot be seen or used inmain.
B. Global scope
A name declared outside all functions is visible to the whole file after its declaration.
- Definition: Global variables are declared above
mainor between functions and can be read or changed by any function below.
Cint count = 0; /* global */ void inc(void){ count++; } /* sees count directly */ - Lifetime: Exist for the entire program run (static storage), keeping their value between calls.
- Shadowing: A local variable with the same name hides the global inside that block; the local wins until the block ends.
- Caution: Globals create hidden dependencies between functions, so prefer parameters and returns where practical.
V. Basics of Pointers — variables that hold addresses
A pointer is a variable whose value is the memory address of another variable, letting code reach data indirectly.
A. Pointer declaration
Declaring a pointer states the type of data it will point to.
- Syntax:
type *name;— the*marks it a pointer,typeis the pointed-to type.
Cint *p; /* pointer to int */ float *q; /* pointer to float */ - Type matters:
int *andfloat *are distinct; the base type sets how many bytes are read and how pointer arithmetic steps.
B. Initialization
A pointer is made to point somewhere using the address-of operator &.
- Address-of
&:&xyields the memory address ofx.
Cint x = 10; int *p = &x; /* p now holds the address of x */ - Null pointer:
int *p = NULL;marks a pointer that points to nothing, guarding against use of an uninitialised address. - Danger: A pointer declared but not initialised holds a garbage address; dereferencing it is undefined behaviour.
C. Accessing values using pointers
The indirection operator * reaches the value stored at the held address.
- Dereference
*:*pmeans "the value at the address inp".
Cint x = 10; int *p = &x; printf("%d", *p); /* prints 10 */ *p = 20; /* changes x to 20 through p */ - Two roles of
*: in a declaration it creates a pointer; in an expression it dereferences one. - Result: editing
*peditsxitself, since both name the same memory.
VI. Passing Arguments by Value and by Address
How arguments reach a function decides whether the caller's own variables can be changed.
A. Passing arguments by value
The function receives copies of the arguments, so the originals are untouched.
- Mechanism: each parameter is a fresh local copy; changes stay inside the function.
Cvoid addOne(int n){ n = n + 1; } /* local copy only */ int a = 5; addOne(a); /* a is still 5 */ - Use when: the function only needs to read the data or return a single new value.
B. Passing arguments by address
The function receives addresses, so it can modify the caller's variables.
- Mechanism: pass
&variable; the parameter is a pointer, and dereferencing it edits the original.
Cvoid addOne(int *n){ *n = *n + 1; } int a = 5; addOne(&a); /* a becomes 6 */ - Contrast:
- By value: safe, isolated, but cannot alter the caller and copies large data.
- By address: can alter the caller and avoids copying, but risks accidental changes.
- Classic use:
swap(int *x, int *y)genuinely exchanges two variables, impossible by value; also lets a function effectively "return" several results.
VII. Recursion — a function that calls itself
Recursion solves a problem by having a function call itself on a smaller version of the same problem.
A. Base case and recursive case
Every correct recursion needs a stopping condition and a self-call that moves toward it.
- Base case: the simplest input, solved directly without recursion; without it the calls never stop (stack overflow).
- Recursive case: the function reduces the problem and calls itself, e.g.
n * factorial(n-1). - The stack: each call is pushed with its own local copies; returns unwind in reverse order.
B. Worked example
int factorial(int n){
if (n == 0) return 1; /* base case */
return n * factorial(n - 1); /* recursive case */
}- Trace of
factorial(3):3 * factorial(2)→3 * 2 * factorial(1)→3 * 2 * 1 * factorial(0)→3 * 2 * 1 * 1 = 6. - Versus iteration: recursion is clearer for naturally self-similar tasks (trees,
gcd), but uses more memory through stacked calls; a loop is cheaper when the logic is flat.
VIII. Library Functions — the standard toolkit
Library functions are the predefined functions grouped into standard header files, giving common operations without reinventing them.
A. Common headers and their functions
Each header declares a family of related routines that you access by including it.
<stdio.h>: input/output —printf,scanf,getchar,fopen.<math.h>: mathematics —sqrt(x),pow(x,y),ceil(x),sin(x); math routines usually take and returndouble.<string.h>: strings —strlen,strcpy,strcat,strcmp.<stdlib.h>: utilities —malloc,free,atoi,rand,exit.<ctype.h>: character tests —isalpha,isdigit,toupper.
B. Linking and use
Including a header only supplies prototypes; the actual code is joined at link time.
#include <math.h>: brings in prototypes so the compiler checks calls; the linker then attaches the compiled library object.- Consistency: these functions behave identically across programs, so
strlen("hello")always returns5. - Practical gain: reliable, portable building blocks let the programmer focus on user defined logic rather than low-level detail.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →