Math Utility Library — abs, power, sqrt, log
Build a mini math library with clean, reusable functions. Each function has a single responsibility. Fast power uses repeated squaring (O(log n) instead of O(n)) — an IIT-favourite optimisation. Custom mySqrt uses the Newton-Raphson method to converge on the square root without importing math.h.
#include <stdio.h> /* Absolute value — works for negatives too */ int myAbs(int n) { return (n < 0) ? -n : n; } /* Fast power: O(log exp) using repeated squaring */ long fastPow(long base, int exp) { long result = 1; while (exp > 0) { if (exp % 2 == 1) /* odd exponent: multiply once */ result *= base; base *= base; /* square the base */ exp /= 2; /* halve the exponent */ } return result; } /* Newton-Raphson square root — no math.h needed */ double mySqrt(double n) { if (n < 0) return -1; /* error */ double guess = n / 2.0; for (int i = 0; i < 50; i++) /* 50 iterations = very precise */ guess = (guess + n / guess) / 2.0; return guess; } /* Greatest common divisor — Euclid's algorithm */ int gcd(int a, int b) { return (b == 0) ? a : gcd(b, a % b); } /* Least common multiple */ int lcm(int a, int b) { return (a / gcd(a, b)) * b; } /* Ceiling division: a / b rounded up */ int ceilDiv(int a, int b) { return (a + b - 1) / b; } int main() { printf("abs(-42) = %d\n", myAbs(-42)); printf("fastPow(2,10) = %ld\n", fastPow(2, 10)); printf("fastPow(3,5) = %ld\n", fastPow(3, 5)); printf("mySqrt(144) = %.4f\n", mySqrt(144)); printf("mySqrt(2) = %.6f\n", mySqrt(2)); printf("gcd(48,18) = %d\n", gcd(48, 18)); printf("lcm(12,18) = %d\n", lcm(12, 18)); printf("ceilDiv(10,3) = %d\n", ceilDiv(10, 3)); /* ceil(10/3)=4 */ return 0; }
abs(-42) = 42 fastPow(2,10) = 1024 fastPow(3,5) = 243 mySqrt(144) = 12.0000 mySqrt(2) = 1.414214 gcd(48,18) = 6 lcm(12,18) = 36 ceilDiv(10,3) = 4
Number Property Checker — Prime, Armstrong, Perfect
Three number property functions that each return 1 (true) or 0 (false). Armstrong number: sum of each digit raised to the power of the number of digits equals the original (153 = 1³+5³+3³). Perfect number: sum of proper divisors equals itself (6 = 1+2+3).
#include <stdio.h> int countDigits(int n) { int count = 0; while (n != 0) { n /= 10; count++; } return count; } long power(int base, int exp) { long r = 1; while (exp--) r *= base; return r; } /* Prime: no divisors from 2 to sqrt(n) */ 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; } /* Armstrong: sum of (each digit ^ numDigits) == n */ int isArmstrong(int n) { int digits = countDigits(n); long sum = 0; int temp = n; while (temp != 0) { sum += power(temp % 10, digits); temp /= 10; } return sum == n; } /* Perfect: sum of proper divisors == n */ int isPerfect(int n) { if (n <= 1) return 0; int sum = 1; for (int i = 2; i * i <= n; i++) if (n % i == 0) { sum += i; if (i != n/i) sum += n/i; } return sum == n; } int main() { int tests[] = {1,2,6,9,17,28,97,153,496}; printf("%-6s %-8s %-12s %-8s\n","N","Prime","Armstrong","Perfect"); printf("-------------------------------------\n"); for (int i=0; i<9; i++) printf("%-6d %-8s %-12s %s\n", tests[i], isPrime(tests[i]) ? "YES" : "no", isArmstrong(tests[i]) ? "YES" : "no", isPerfect(tests[i]) ? "YES" : "no"); return 0; }
N Prime Armstrong Perfect ------------------------------------- 1 no YES no 2 YES no no 6 no no YES 9 no no no 17 YES no no 28 no no YES 97 YES no no 153 no YES no 496 no no YES
Correct Swap + Three Sorting Functions
The correct swap using pointers, then three classic sorting algorithms each packaged as a clean reusable function. Insertion sort is the most efficient for nearly-sorted arrays and is used inside sort algorithms like Timsort.
#include <stdio.h> void swap(int *a, int *b) { int t = *a; *a = *b; *b = t; } void printArr(int a[], int n) { for(int i=0;i<n;i++) printf("%d ",a[i]); printf("\n"); } /* Bubble Sort: O(n²) — compare adjacent, bubble max to end */ void bubbleSort(int arr[], int n) { for (int i=0; i<n-1; i++) { int swapped = 0; for (int j=0; j<n-i-1; j++) if (arr[j] > arr[j+1]) { swap(&arr[j],&arr[j+1]); swapped=1; } if (!swapped) break; /* optimisation: stop if already sorted */ } } /* Selection Sort: O(n²) — find min, place at front */ void selectionSort(int arr[], int n) { for (int i=0; i<n-1; i++) { int minIdx = i; for (int j=i+1; j<n; j++) if (arr[j] < arr[minIdx]) minIdx = j; if (minIdx != i) swap(&arr[i], &arr[minIdx]); } } /* Insertion Sort: O(n²) worst, O(n) for nearly sorted */ void insertionSort(int arr[], int n) { for (int i=1; i<n; i++) { int key = arr[i], j = i-1; while (j >= 0 && arr[j] > key) { arr[j+1] = arr[j]; j--; } arr[j+1] = key; } } int main() { int a[] = {64,25,12,92,43}; int b[] = {64,25,12,92,43}; int c[] = {64,25,12,92,43}; bubbleSort(a,5); printf("Bubble: "); printArr(a,5); selectionSort(b,5); printf("Selection: "); printArr(b,5); insertionSort(c,5); printf("Insertion: "); printArr(c,5); return 0; }
Bubble: 12 25 43 64 92 Selection: 12 25 43 64 92 Insertion: 12 25 43 64 92
swapped flag becomes O(n) on already-sorted input. Insertion sort makes fewer comparisons and is stable — equal elements keep their original order. Selection sort always makes exactly n-1 swaps regardless of input.Fibonacci — Recursive vs Iterative vs Memoised
Call tree for fib(5) — recursive makes 15 calls, iterative makes 5 steps
#include <stdio.h> #include <string.h> int callCount = 0; /* count recursive calls */ /* Method 1: Naive recursive — O(2^n) calls */ int fibRec(int n) { callCount++; if (n <= 1) return n; return fibRec(n-1) + fibRec(n-2); } /* Method 2: Iterative — O(n) time, O(1) space */ long fibIter(int n) { if (n <= 1) return n; long a=0, b=1, c; for (int i=2; i<=n; i++) { c=a+b; a=b; b=c; } return b; } /* Method 3: Memoised recursive — O(n) time via cache */ #define MAXN 50 long memo[MAXN]; long fibMemo(int n) { if (n <= 1) return n; if (memo[n] != -1) return memo[n]; /* already computed! */ return memo[n] = fibMemo(n-1) + fibMemo(n-2); } int main() { printf("Fibonacci Comparison (n=10):\n"); printf("%-10s %-10s %-12s %s\n","n","Recursive","Iterative","Memo"); printf("--------------------------------------------\n"); for (int n=0; n<=10; n++) { callCount = 0; memset(memo, -1, sizeof(memo)); int r = fibRec(n); printf("%-10d %-10d %-12ld %ld (calls=%d)\n", n, r, fibIter(n), fibMemo(n), callCount); } return 0; }
n Recursive Iterative Memo -------------------------------------------- 0 0 0 0 (calls=1) 1 1 1 1 (calls=1) 5 5 5 5 (calls=15) 8 21 21 21 (calls=67) 10 55 55 55 (calls=177)
Pascal's Triangle Using Recursive Combination
#include <stdio.h> /* nCr = n! / (r! * (n-r)!) — computed recursively Base: nC0 = 1, nCn = 1 Rule: nCr = (n-1)C(r-1) + (n-1)Cr */ long nCr(int n, int r) { if (r == 0 || r == n) return 1; /* base: edges are 1 */ return nCr(n-1, r-1) + nCr(n-1, r); /* Pascal's rule */ } void printPascal(int rows) { for (int n = 0; n < rows; n++) { /* Print leading spaces for triangle shape */ for (int sp = 0; sp < rows-n-1; sp++) printf(" "); for (int r = 0; r <= n; r++) printf("%5ld ", nCr(n, r)); printf("\n"); } } /* Binomial expansion: (a+b)^n coefficients */ void binomialExpand(int n) { printf("(a+b)^%d = ", n); for (int r = 0; r <= n; r++) { long coef = nCr(n, r); if (r > 0) printf(" + "); if (coef > 1) printf("%ld", coef); if (r < n) printf("a^%d", n-r); if (r > 0 && r < n) printf("b^%d", r); if (r == n) printf("b^%d", n); } printf("\n"); } int main() { printf("Pascal's Triangle (6 rows):\n\n"); printPascal(6); printf("\nBinomial Expansions:\n"); binomialExpand(3); binomialExpand(4); return 0; }
Pascal's Triangle (6 rows):
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
Binomial Expansions:
(a+b)^3 = a^3 + 3a^2b^1 + 3a^1b^2 + b^3
(a+b)^4 = a^4 + 4a^3b^1 + 6a^2b^2 + 4a^1b^3 + b^4
String Processing Functions — Full Utility Set
#include <stdio.h> #include <ctype.h> int myLen(char *s) { int i=0; while(s[i]) i++; return i; } void toUpper(char *s) { for(int i=0;s[i];i++) s[i]=toupper(s[i]); } void toLower(char *s) { for(int i=0;s[i];i++) s[i]=tolower(s[i]); } /* Reverse string in-place using two-pointer swap */ void reverse(char *s) { int l=0, r=myLen(s)-1; while(l<r) { char t=s[l]; s[l++]=s[r]; s[r--]=t; } } /* Palindrome check — compare from both ends */ int isPalindrome(char *s) { int l=0, r=myLen(s)-1; while(l<r) if(tolower(s[l++])!=tolower(s[r--])) return 0; return 1; } /* Count occurrences of a character */ int countCh(char *s, char c) { int cnt=0; for(int i=0;s[i];i++) if(tolower(s[i])==tolower(c)) cnt++; return cnt; } /* Find first occurrence, return index or -1 */ int findCh(char *s, char c) { for(int i=0;s[i];i++) if(s[i]==c) return i; return -1; } /* Remove all spaces from string */ void removeSpaces(char *s) { int i=0, j=0; while(s[i]) { if(s[i]!=' ') s[j++]=s[i]; i++; } s[j]='\0'; } /* Count words (sequences separated by spaces) */ int wordCount(char *s) { int cnt=0, inWord=0; for(int i=0;s[i];i++){ if(s[i]!=' '){ if(!inWord){ cnt++; inWord=1; }} else inWord=0; } return cnt; } int main() { char s1[] = "Hello World"; char s2[] = "racecar"; char s3[] = "Hello Ananta Code"; printf("len(\"%s\") = %d\n", s1, myLen(s1)); printf("words(\"%s\") = %d\n", s1, wordCount(s1)); printf("isPalin(\"%s\") = %d\n", s2, isPalindrome(s2)); printf("isPalin(\"%s\") = %d\n", s1, isPalindrome(s1)); printf("countCh l in \"%s\" = %d\n", s1, countCh(s1,'l')); printf("findCh 'W' = %d\n", findCh(s1,'W')); toUpper(s1); printf("toUpper: %s\n", s1); reverse(s2); printf("reverse: %s\n", s2); removeSpaces(s3); printf("noSpaces: %s\n", s3); return 0; }
len("Hello World") = 11
words("Hello World") = 2
isPalin("racecar") = 1
isPalin("Hello World") = 0
countCh l in "Hello World" = 3
findCh 'W' = 6
toUpper: HELLO WORLD
reverse: racecar
noSpaces: HelloAnantaCode
Multiple Return Values via Output Pointers
C functions can only return one value directly. When you need multiple results, pass output pointers as parameters and write results into them. This is exactly how scanf works — it receives addresses and writes values at those addresses.
#include <stdio.h> #include <math.h> /* Returns min AND max in one call using output pointers */ void findMinMax(int arr[], int n, int *minOut, int *maxOut) { *minOut = *maxOut = arr[0]; for (int i=1; i<n; i++) { if (arr[i] < *minOut) *minOut = arr[i]; if (arr[i] > *maxOut) *maxOut = arr[i]; } } /* Returns sum AND average together */ void sumAvg(int arr[], int n, int *sumOut, float *avgOut) { *sumOut = 0; for (int i=0; i<n; i++) *sumOut += arr[i]; *avgOut = (float)*sumOut / n; } /* Quadratic formula: returns root count, writes roots to r1, r2 */ int quadratic(float a, float b, float c, float *r1, float *r2) { float disc = b*b - 4*a*c; if (disc < 0) return 0; /* no real roots */ if (disc == 0) { *r1 = *r2 = -b / (2*a); return 1; /* one repeated root */ } *r1 = (-b + sqrt(disc)) / (2*a); *r2 = (-b - sqrt(disc)) / (2*a); return 2; /* two distinct roots */ } int main() { int arr[] = {40,12,75,3,58,29}; int mn, mx, s; float av; findMinMax(arr, 6, &mn, &mx); sumAvg(arr, 6, &s, &av); printf("Min=%d Max=%d Sum=%d Avg=%.1f\n", mn, mx, s, av); float r1, r2; int roots = quadratic(1, -5, 6, &r1, &r2); /* x²-5x+6=0 */ printf("x²-5x+6: roots=%d r1=%.1f r2=%.1f\n", roots, r1, r2); roots = quadratic(1, 2, 5, &r1, &r2); /* x²+2x+5=0 */ printf("x²+2x+5: roots=%d (imaginary)\n", roots); return 0; }
Min=3 Max=75 Sum=217 Avg=36.2 x²-5x+6: roots=2 r1=3.0 r2=2.0 x²+2x+5: roots=0 (imaginary)
Recursive Patterns — Stars, Numbers, Binary
#include <stdio.h> /* Countdown then countup — output BEFORE and AFTER recursion */ void countDown(int n) { if (n == 0) { printf("0 "); return; } printf("%d ", n); /* print BEFORE recursion → countdown */ countDown(n - 1); printf("%d ", n); /* print AFTER recursion → countup */ } /* Decimal to binary — recursion prints most-significant bit first */ void toBinary(int n) { if (n == 0) return; toBinary(n / 2); /* recurse FIRST — MSB printed last */ printf("%d", n % 2); /* print on RETURN — so left to right */ } /* Sum of array recursively */ int arrSum(int arr[], int n) { if (n == 0) return 0; return arr[n-1] + arrSum(arr, n-1); /* peel off last element */ } /* Check if array is sorted recursively */ int isSorted(int arr[], int n) { if (n <= 1) return 1; /* 0 or 1 element — always sorted */ if (arr[0] > arr[1]) return 0; /* first pair unsorted → false */ return isSorted(arr+1, n-1); /* check rest of array */ } /* Recursive print of digits (rightmost first) */ void printDigits(int n) { if (n < 10) { printf("%d\n", n); return; } printDigits(n / 10); printf("%d\n", n % 10); } int main() { printf("countDown(4): "); countDown(4); printf("\n"); printf("toBinary(42) = "); toBinary(42); printf("\n"); printf("toBinary(255) = "); toBinary(255); printf("\n"); int a[] = {10,20,30,40}; int b[] = {10,5,30}; printf("arrSum={10,20,30,40} = %d\n", arrSum(a,4)); printf("isSorted(a) = %d\n", isSorted(a,4)); printf("isSorted(b) = %d\n", isSorted(b,3)); printf("digits of 9875:\n"); printDigits(9875); return 0; }
countDown(4): 4 3 2 1 0 1 2 3 4
toBinary(42) = 101010
toBinary(255) = 11111111
arrSum={10,20,30,40} = 100
isSorted(a) = 1
isSorted(b) = 0
digits of 9875:
9
8
7
5
Advanced Array Functions — Rotate, Merge, Remove Dups
#include <stdio.h> void print(int a[], int n) { for(int i=0;i<n;i++) printf("%d ",a[i]); printf("\n"); } /* Left rotate array by k positions */ void rotateLeft(int arr[], int n, int k) { k %= n; /* handle k > n */ for (int i=0; i<k; i++) { int t=arr[0]; for(int j=0;j<n-1;j++) arr[j]=arr[j+1]; arr[n-1]=t; } } /* Remove duplicates from sorted array, return new length */ int removeDups(int arr[], int n) { if (n==0) return 0; int j=0; for(int i=1;i<n;i++) if(arr[i]!=arr[j]) arr[++j]=arr[i]; return j+1; } /* Merge two sorted arrays into result[] */ int mergeSorted(int a[], int na, int b[], int nb, int res[]) { int i=0, j=0, k=0; while(i<na && j<nb) res[k++]=(a[i]<b[j])?a[i++]:b[j++]; while(i<na) res[k++]=a[i++]; while(j<nb) res[k++]=b[j++]; return na+nb; } /* Find majority element (appears > n/2 times) — Boyer-Moore */ int majorityElem(int arr[], int n) { int candidate=arr[0], count=1; for(int i=1;i<n;i++){ count += (arr[i]==candidate) ? 1 : -1; if(count==0){ candidate=arr[i]; count=1; } } return candidate; } int main() { int a[] = {1,2,3,4,5}; printf("Original: "); print(a,5); rotateLeft(a,5,2); printf("Rotate L2: "); print(a,5); int d[] = {1,1,2,3,3,4,4,4,5}; int len = removeDups(d,9); printf("RemoveDups: "); print(d,len); int b[]={1,3,5}, c[]={2,4,6}, merged[6]; mergeSorted(b,3,c,3,merged); printf("Merged: "); print(merged,6); int m[] = {3,3,4,2,3}; printf("Majority elem = %d\n", majorityElem(m,5)); return 0; }
Original: 1 2 3 4 5 Rotate L2: 3 4 5 1 2 RemoveDups: 1 2 3 4 5 Merged: 1 2 3 4 5 6 Majority elem = 3
Complete Student Grade System — All Techniques Combined
A complete academic program that combines every function technique: void functions for display, float-returning functions for averages, char-returning functions for grades, pointer parameters for statistics, sorting using function-based bubble sort, and string arrays for names.
#include <stdio.h> #include <string.h> #define STU 5 #define SUB 4 char names[STU][20] = {"Ananta","Priya","Rahul","Vikram","Sneha"}; int marks[STU][SUB]= {{92,85,98,88},{78,82,75,90}, {60,55,70,65},{88,90,85,92},{95,93,97,96}}; /* Return average marks for one student */ float getAvg(int idx) { int sum=0; for(int j=0;j<SUB;j++) sum+=marks[idx][j]; return (float)sum/SUB; } /* Return grade char based on average */ char getGrade(float avg) { if(avg>=90) return 'A'; if(avg>=75) return 'B'; if(avg>=55) return 'C'; return 'F'; } /* Find class topper and average — output pointers */ void classStats(int *topperIdx, float *classAvg) { float total=0; *topperIdx=0; float best = getAvg(0); for(int i=0;i<STU;i++){ float a=getAvg(i); total+=a; if(a>best){ best=a; *topperIdx=i; } } *classAvg = total/STU; } /* Sort students by average descending (bubble sort) */ void sortByAvg() { for(int i=0;i<STU-1;i++) for(int j=0;j<STU-i-1;j++) if(getAvg(j)<getAvg(j+1)){ /* swap entire rows of marks and names */ int tmpM[SUB]; char tmpN[20]; memcpy(tmpM,marks[j],sizeof(tmpM)); memcpy(marks[j],marks[j+1],sizeof(tmpM)); memcpy(marks[j+1],tmpM,sizeof(tmpM)); strcpy(tmpN,names[j]); strcpy(names[j],names[j+1]); strcpy(names[j+1],tmpN); } } /* Print formatted report card */ void printReport() { printf("%-10s %4s %4s %4s %4s Avg Grade\n", "Name","M1","M2","M3","M4"); printf("-------------------------------------------\n"); for(int i=0;i<STU;i++){ float avg=getAvg(i); printf("%-10s %4d %4d %4d %4d %4.1f %c\n", names[i],marks[i][0],marks[i][1],marks[i][2],marks[i][3], avg,getGrade(avg)); } } int main() { int topIdx; float clsAvg; printf("=== ORIGINAL REPORT ===\n"); printReport(); classStats(&topIdx, &clsAvg); printf("Class Average: %.1f\n", clsAvg); printf("Topper: %s (%.1f)\n", names[topIdx], getAvg(topIdx)); printf("\n=== SORTED BY AVERAGE (HIGH TO LOW) ===\n"); sortByAvg(); printReport(); return 0; }
=== ORIGINAL REPORT === Name M1 M2 M3 M4 Avg Grade ------------------------------------------- Ananta 92 85 98 88 90.8 A Priya 78 82 75 90 81.3 B Rahul 60 55 70 65 62.5 C Vikram 88 90 85 92 88.8 B Sneha 95 93 97 96 95.3 A Class Average: 83.7 Topper: Sneha (95.3) === SORTED BY AVERAGE (HIGH TO LOW) === Name M1 M2 M3 M4 Avg Grade ------------------------------------------- Sneha 95 93 97 96 95.3 A Ananta 92 85 98 88 90.8 A Vikram 88 90 85 92 88.8 B Priya 78 82 75 90 81.3 B Rahul 60 55 70 65 62.5 C
Examples Mastery Checklist
- E1 — I understand fast power O(log n) using repeated squaring
- E1 — I can explain Newton-Raphson sqrt without math.h
- E2 — I can write isPrime using i*i <= n loop (O(√n))
- E2 — I know Armstrong number: sum of digit^numDigits == n
- E3 — I can write bubble, selection, and insertion sort as functions
- E3 — I know which sort is best for nearly-sorted arrays (insertion)
- E4 — I understand why recursive Fibonacci is O(2ⁿ) — repeated subproblems
- E4 — I can implement memoised Fibonacci using a static cache array
- E5 — I know Pascal's rule: nCr = (n-1)C(r-1) + (n-1)Cr
- E6 — I can write in-place string functions using char pointer parameters
- E7 — I can use output pointer parameters to return multiple values
- E8 — I understand print-before vs print-after recursion gives different outputs
- E9 — I can implement rotate, removeDups, merge sorted arrays as functions
- E10 — I can combine all function types in one complete program