functions in C exercises pass by reference solutions cheat sheet IC2 Fedora

Functions in C exercises — master pass by reference

Functions in C exercises are where pass by value and pass by reference stop being abstract concepts and become tools you apply automatically. You’ve seen the theory and built three complete programs. Now it’s time to solve challenges on your own — finding the second maximum, deleting an element by position, and merging two sorted arrays.

Set up your workspace:

cd ~/GCID/IC2/Labs
mkdir exercises_functions
cd exercises_functions

As always: try to solve it in gedit, compile with gcc, use the hint if stuck for more than 10 minutes, and compare with the commented solution.


Functions in c exercises — Basic Level

Exercise 1 — Second maximum

Write a C program with these functions for integer arrays:

  • find_second_max(arr, n, *second) — finds the second largest distinct value. Returns 1 if found (at least 2 distinct values exist), 0 otherwise. Returns the value through the pointer.
  • find_top_k(arr, n, k, result) — fills result with the top k distinct values in descending order. Returns the number of distinct values actually found (may be less than k).
  • count_distinct(arr, n) — returns how many distinct values exist in the array.
Array: [3, 1, 4, 1, 5, 9, 2, 6, 5, 3]

Distinct values: 7
Maximum:         9
Second maximum:  6

Top 3: [9, 6, 5]
Top 5: [9, 6, 5, 4, 3]
Top 10: [9, 6, 5, 4, 3, 2, 1] (only 7 distinct values)

💡 Hints:

  • find_second_max: traverse once tracking max and second_max. When arr[i] > max: second_max = max; max = arr[i]. When arr[i] > second_max && arr[i] != max: second_max = arr[i].
  • count_distinct: for each element, check if it appeared earlier in the array. If not, count it.
  • find_top_k: sort a copy of the array descending, then collect distinct values until you have k or run out.
  • Pass second as int *second and write *second = value inside the function.

Exercise 2 — Delete element by position

Write a C program with these functions:

  • delete_at(arr, *n, index) — removes the element at index, shifts all subsequent elements left, decrements *n. Returns 1 if successful, 0 if index out of range.
  • delete_value(arr, *n, value) — removes the first occurrence of value. Returns 1 if found and removed, 0 if not found.
  • delete_all(arr, *n, value) — removes ALL occurrences of value. Returns the number of deletions.
  • insert_at(arr, *n, index, value, max_size) — inserts value at index, shifts elements right. Returns 1 if successful, 0 if array is full or index out of range.
Array: [1, 2, 3, 4, 5, 3, 6, 3]  n=8

delete_at(arr, &n, 2):  [1, 2, 4, 5, 3, 6, 3]  n=7
delete_value(arr, &n, 3): [1, 2, 4, 5, 3, 6, 3] → removes first 3
delete_all(arr, &n, 3):  removes all 3s
insert_at(arr, &n, 1, 99, MAX): inserts 99 at position 1

💡 Hints:

  • delete_at: shift left: for (i = index; i < n-1; i++) arr[i] = arr[i+1]; (*n)--;
  • delete_value: find the index of the first occurrence, then call delete_at
  • delete_all: walk with two indices — read and write. Copy elements that don’t match, skip those that do. Update *n at the end.
  • insert_at: first check bounds and *n < max_size. Shift right: for (i = *n; i > index; i--) arr[i] = arr[i-1]. Then set arr[index] = value; (*n)++;
  • *n is a pointer to int — you need (*n)-- not *n-- (operator precedence)

Functions in c exercises — Intermediate Level → Final Challenge

Exercise 3 — Merge two sorted arrays

Write a C program that merges two sorted integer arrays into a single sorted array — without using any sorting function on the result. The merge must be done in O(n+m) time using the two-pointer technique.

Also implement:

  • intersection(a, na, b, nb, result, *nr) — elements that appear in both arrays
  • union_arrays(a, na, b, nb, result, *nr) — all distinct elements from both arrays
  • difference(a, na, b, nb, result, *nr) — elements in a that are not in b

All input arrays are sorted. All result arrays must also be sorted.

A = [1, 3, 5, 7, 9]       (sorted)
B = [2, 3, 4, 7, 8, 10]   (sorted)

Merge:        [1, 2, 3, 3, 4, 5, 7, 7, 8, 9, 10]
Intersection: [3, 7]
Union:        [1, 2, 3, 4, 5, 7, 8, 9, 10]
Difference A-B: [1, 5, 9]

💡 Hints:

  • Merge: use two indices i=0, j=0. While both in range: take the smaller and advance its index. When one runs out, copy the rest of the other.
  • Intersection: advance through both. When a[i] == b[j], add to result and advance both. When a[i] < b[j], advance i. Otherwise advance j.
  • Union: similar to merge but skip duplicates — when both have the same value, add once and advance both.
  • Difference: advance through a. For each a[i], binary search in b to check if it exists. If not found, add to result.

Commented solutions

Solution Exercise 1

#include <stdio.h>

#define MAX 100

void print_array(const int *arr, int n) {
    printf("[");
    for (int i = 0; i < n; i++) {
        printf("%d", arr[i]);
        if (i < n - 1) printf(", ");
    }
    printf("]");
}

int count_distinct(const int *arr, int n) {
    int count = 0;
    for (int i = 0; i < n; i++) {
        int already_seen = 0;
        for (int j = 0; j < i; j++) {
            if (arr[j] == arr[i]) {
                already_seen = 1;
                break;
            }
        }
        if (!already_seen) count++;
    }
    return count;
}

int find_max(const int *arr, int n) {
    int max = arr[0];
    for (int i = 1; i < n; i++)
        if (arr[i] > max) max = arr[i];
    return max;
}

int find_second_max(const int *arr, int n, int *second) {
    if (count_distinct(arr, n) < 2)
        return 0;    /* need at least 2 distinct values */

    int max = find_max(arr, n);
    int sec = -2147483648;    /* INT_MIN */
    int found = 0;

    for (int i = 0; i < n; i++) {
        if (arr[i] != max && arr[i] > sec) {
            sec = arr[i];
            found = 1;
        }
    }
    if (found) *second = sec;
    return found;
}

/* Sort a copy descending and collect distinct values */
int find_top_k(const int *arr, int n, int k, int *result) {
    /* Make a sorted copy */
    int copy[MAX];
    for (int i = 0; i < n; i++) copy[i] = arr[i];

    /* Bubble sort descending */
    for (int i = 0; i < n - 1; i++)
        for (int j = 0; j < n - 1 - i; j++)
            if (copy[j] < copy[j+1]) {
                int tmp = copy[j];
                copy[j] = copy[j+1];
                copy[j+1] = tmp;
            }

    /* Collect k distinct values */
    int count = 0;
    for (int i = 0; i < n && count < k; i++) {
        if (i == 0 || copy[i] != copy[i-1]) {
            result[count++] = copy[i];
        }
    }
    return count;
}

int main() {
    int arr[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
    int n = 10;

    printf("Array: ");
    print_array(arr, n);
    printf("\n\n");

    printf("Distinct values: %d\n", count_distinct(arr, n));
    printf("Maximum:         %d\n", find_max(arr, n));

    int second;
    if (find_second_max(arr, n, &second))
        printf("Second maximum:  %d\n", second);
    else
        printf("No second maximum (all values equal)\n");

    printf("\n");
    int top[MAX], found;
    int k_values[] = {3, 5, 10};

    for (int t = 0; t < 3; t++) {
        int k = k_values[t];
        found = find_top_k(arr, n, k, top);
        printf("Top %2d: ", k);
        print_array(top, found);
        if (found < k)
            printf(" (only %d distinct values)", found);
        printf("\n");
    }

    /* Edge cases */
    int all_same[] = {5, 5, 5};
    printf("\nAll same [5,5,5]: second_max = ");
    if (find_second_max(all_same, 3, &second))
        printf("%d\n", second);
    else
        printf("none\n");

    return 0;
}

Solution Exercise 2

#include <stdio.h>

#define MAX 50

void print_array(const int *arr, int n) {
    printf("[");
    for (int i = 0; i < n; i++) {
        printf("%d", arr[i]);
        if (i < n - 1) printf(", ");
    }
    printf("] n=%d\n", n);
}

int delete_at(int *arr, int *n, int index) {
    if (index < 0 || index >= *n)
        return 0;    /* out of range */
    for (int i = index; i < *n - 1; i++)
        arr[i] = arr[i+1];    /* shift left */
    (*n)--;
    return 1;
}

int delete_value(int *arr, int *n, int value) {
    for (int i = 0; i < *n; i++) {
        if (arr[i] == value)
            return delete_at(arr, n, i);
    }
    return 0;    /* not found */
}

int delete_all(int *arr, int *n, int value) {
    int write = 0, removed = 0;
    for (int read = 0; read < *n; read++) {
        if (arr[read] != value) {
            arr[write++] = arr[read];
        } else {
            removed++;
        }
    }
    *n = write;
    return removed;
}

int insert_at(int *arr, int *n, int index, int value, int max_size) {
    if (*n >= max_size || index < 0 || index > *n)
        return 0;    /* full or out of range */
    for (int i = *n; i > index; i--)
        arr[i] = arr[i-1];    /* shift right */
    arr[index] = value;
    (*n)++;
    return 1;
}

int main() {
    int arr[MAX] = {1, 2, 3, 4, 5, 3, 6, 3};
    int n = 8;

    printf("Original:   ");
    print_array(arr, n);

    /* delete_at */
    int arr2[MAX];
    for (int i = 0; i < n; i++) arr2[i] = arr[i];
    int n2 = n;

    delete_at(arr2, &n2, 2);
    printf("delete_at(2): ");
    print_array(arr2, n2);

    /* delete_value */
    int arr3[MAX];
    for (int i = 0; i < n; i++) arr3[i] = arr[i];
    int n3 = n;

    int found = delete_value(arr3, &n3, 3);
    printf("delete_value(3): ");
    print_array(arr3, n3);
    printf("  → removed: %s\n", found ? "yes" : "no");

    /* delete_all */
    int arr4[MAX];
    for (int i = 0; i < n; i++) arr4[i] = arr[i];
    int n4 = n;

    int removed = delete_all(arr4, &n4, 3);
    printf("delete_all(3):   ");
    print_array(arr4, n4);
    printf("  → removed %d occurrence(s)\n", removed);

    /* insert_at */
    int arr5[MAX];
    for (int i = 0; i < n4; i++) arr5[i] = arr4[i];
    int n5 = n4;

    insert_at(arr5, &n5, 1, 99, MAX);
    printf("insert_at(1, 99): ");
    print_array(arr5, n5);

    /* Edge cases */
    printf("\n--- Edge cases ---\n");
    int small[] = {10, 20, 30};
    int ns = 3;
    printf("delete_at(-1) returns: %d\n", delete_at(small, &ns, -1));
    printf("delete_at(3)  returns: %d\n", delete_at(small, &ns, 3));
    printf("delete_value(99) returns: %d\n", delete_value(small, &ns, 99));

    return 0;
}

Solution Exercise 3

#include <stdio.h>

#define MAX 200

void print_array(const int *arr, int n, const char *label) {
    printf("%s[", label);
    for (int i = 0; i < n; i++) {
        printf("%d", arr[i]);
        if (i < n - 1) printf(", ");
    }
    printf("] (n=%d)\n", n);
}

/* Merge two sorted arrays — O(n+m) */
void merge_sorted(const int *a, int na,
                  const int *b, int nb,
                  int *result, int *nr) {
    int i = 0, j = 0, k = 0;

    while (i < na && j < nb) {
        if (a[i] <= b[j])
            result[k++] = a[i++];
        else
            result[k++] = b[j++];
    }
    /* Copy remaining elements */
    while (i < na) result[k++] = a[i++];
    while (j < nb) result[k++] = b[j++];
    *nr = k;
}

/* Elements in both A and B */
void intersection(const int *a, int na,
                  const int *b, int nb,
                  int *result, int *nr) {
    int i = 0, j = 0, k = 0;
    int prev = -2147483648;    /* track duplicates in result */

    while (i < na && j < nb) {
        if (a[i] == b[j]) {
            if (a[i] != prev) {    /* avoid duplicates in result */
                result[k++] = a[i];
                prev = a[i];
            }
            i++;
            j++;
        } else if (a[i] < b[j]) {
            i++;
        } else {
            j++;
        }
    }
    *nr = k;
}

/* All distinct elements from A and B */
void union_arrays(const int *a, int na,
                  const int *b, int nb,
                  int *result, int *nr) {
    int i = 0, j = 0, k = 0;
    int prev = -2147483648;

    while (i < na && j < nb) {
        int val;
        if (a[i] < b[j])       val = a[i++];
        else if (b[j] < a[i])  val = b[j++];
        else { val = a[i++]; j++; }    /* same — take once, advance both */

        if (val != prev) {
            result[k++] = val;
            prev = val;
        }
    }
    while (i < na) {
        if (a[i] != prev) { result[k++] = a[i]; prev = a[i]; }
        i++;
    }
    while (j < nb) {
        if (b[j] != prev) { result[k++] = b[j]; prev = b[j]; }
        j++;
    }
    *nr = k;
}

/* Binary search — returns 1 if found, 0 otherwise */
int binary_search(const int *arr, int n, int target) {
    int lo = 0, hi = n - 1;
    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;
        if (arr[mid] == target) return 1;
        if (arr[mid] < target)  lo = mid + 1;
        else                    hi = mid - 1;
    }
    return 0;
}

/* Elements in A that are not in B */
void difference(const int *a, int na,
                const int *b, int nb,
                int *result, int *nr) {
    int k = 0;
    int prev = -2147483648;
    for (int i = 0; i < na; i++) {
        if (a[i] != prev && !binary_search(b, nb, a[i])) {
            result[k++] = a[i];
            prev = a[i];
        }
    }
    *nr = k;
}

int main() {
    int a[] = {1, 3, 5, 7, 9};
    int b[] = {2, 3, 4, 7, 8, 10};
    int na = 5, nb = 6;

    printf("=== SORTED ARRAY OPERATIONS ===\n\n");
    print_array(a, na, "A = ");
    print_array(b, nb, "B = ");
    printf("\n");

    int result[MAX];
    int nr;

    merge_sorted(a, na, b, nb, result, &nr);
    print_array(result, nr, "Merge:        ");

    intersection(a, na, b, nb, result, &nr);
    print_array(result, nr, "Intersection: ");

    union_arrays(a, na, b, nb, result, &nr);
    print_array(result, nr, "Union:        ");

    difference(a, na, b, nb, result, &nr);
    print_array(result, nr, "Difference A-B: ");

    difference(b, nb, a, na, result, &nr);
    print_array(result, nr, "Difference B-A: ");

    /* Edge cases */
    printf("\n--- Edge cases ---\n");
    int empty[] = {};
    merge_sorted(a, na, empty, 0, result, &nr);
    print_array(result, nr, "Merge A+empty: ");

    int identical[] = {1, 3, 5, 7, 9};
    intersection(a, na, identical, 5, result, &nr);
    print_array(result, nr, "Intersection identical: ");

    return 0;
}

Visualise with Python Tutor

Select C from the dropdown and paste in pythontutor.com:

#include <stdio.h>

int delete_at(int *arr, int *n, int index) {
    if (index < 0 || index >= *n) return 0;
    for (int i = index; i < *n - 1; i++)
        arr[i] = arr[i+1];
    (*n)--;
    return 1;
}

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int n = 5;

    printf("Before: ");
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("n=%d\n", n);

    delete_at(arr, &n, 1);    /* delete element at index 1 (value 20) */

    printf("After:  ");
    for (int i = 0; i < n; i++) printf("%d ", arr[i]);
    printf("n=%d\n", n);

    return 0;
}

Step through delete_at carefully. When called, arr receives the address of arr[0] in main — an arrow pointing into main’s array. n receives the address of main’s n variable — another arrow. Inside the function, *n reads through that arrow: it sees 5. The shift loop arr[i] = arr[i+1] follows the arr arrow and modifies main’s array directly — you can see the values shifting left in Python Tutor’s memory diagram. Then (*n)-- — note the parentheses — dereferences n first (getting 5), then decrements what’s stored at that address (now 4). Without parentheses *n-- would decrement the pointer itself, not the value — a subtle but critical difference. After the function returns, main’s arr has shifted elements and main’s n is 4.


Cheat sheet — Functions in C

/* ============================================
   CHEAT SHEET — Functions in C
   Sergio Learns · sergiolearns.com
   ============================================ */

/* FUNCTION STRUCTURE */
return_type name(type param1, type param2) {
    /* body */
    return value;    /* void functions use bare return; */
}

/* PROTOTYPE — declare before calling */
int add(int a, int b);          /* full declaration */
int add(int, int);              /* parameter names optional */

/* VOID — no return value */
void print_info(int x) {
    printf("%d\n", x);
    /* optional: return; to exit early */
}

/* PASS BY VALUE — function gets a copy */
void f_value(int n) { n = 99; }
int x = 5;
f_value(x);
/* x is still 5 */

/* PASS BY REFERENCE — function gets the address */
void f_ref(int *p) { *p = 99; }
int x = 5;
f_ref(&x);    /* & gives the address */
/* x is now 99 */

/* MULTIPLE RETURN VALUES — through pointer params */
void divide(int a, int b, int *q, int *r) {
    *q = a / b;
    *r = a % b;
}
int q, r;
divide(17, 5, &q, &r);    /* q=3, r=2 */

/* ARRAYS — always passed by reference (pointer) */
void process(int *arr, int n) { arr[i] = ...; }
process(numbers, n);       /* no & needed — arr name IS &arr[0] */

/* const — read-only parameter */
void print(const int *arr, int n) {
    /* arr[i] = 0; → compile error */
}

/* DELETE ELEMENT — shift pattern */
void delete_at(int *arr, int *n, int idx) {
    for (int i = idx; i < *n - 1; i++)
        arr[i] = arr[i+1];    /* shift left */
    (*n)--;                   /* (*n)-- not *n-- */
}

/* INSERT ELEMENT — shift pattern */
void insert_at(int *arr, int *n, int idx, int val) {
    for (int i = *n; i > idx; i--)
        arr[i] = arr[i-1];    /* shift right */
    arr[idx] = val;
    (*n)++;
}

/* MERGE TWO SORTED ARRAYS — two-pointer O(n+m) */
void merge(int *a, int na, int *b, int nb,
           int *result, int *nr) {
    int i = 0, j = 0, k = 0;
    while (i < na && j < nb)
        result[k++] = (a[i] <= b[j]) ? a[i++] : b[j++];
    while (i < na) result[k++] = a[i++];
    while (j < nb) result[k++] = b[j++];
    *nr = k;
}

/* FIND SECOND MAX — single pass */
void second_max(int *arr, int n, int *max, int *sec) {
    *max = *sec = -2147483648;    /* INT_MIN */
    for (int i = 0; i < n; i++) {
        if (arr[i] > *max) { *sec = *max; *max = arr[i]; }
        else if (arr[i] > *sec && arr[i] != *max)
            *sec = arr[i];
    }
}

/* COMMON MISTAKES */
/* 1. Forgetting & in call: f(x) vs f(&x) */
/* 2. (*n)-- vs *n-- (precedence: *n-- decrements pointer) */
/* 3. Calling without prototype before definition */
/* 4. Returning local array — it disappears after return */
/* 5. Not checking bounds before delete/insert */
/* 6. Modifying read-only const parameter */

/* COMPILE AND RUN */
/* gcc exercise.c -o exercise -Wall */
/* ./exercise                        */

Similar Posts

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *