pointers in C exercises solutions cheat sheet memory Fedora

Pointers in C exercises — master memory

Pointers in C exercises are where the mental model becomes instinct. You’ve seen the theory and built four complete programs. Now it’s time to solve challenges on your own in Fedora — copying arrays with pointers, counting and replacing elements, and a final challenge that implements a basic dynamic data structure.

Set up your workspace:

cd ~/GCID/IC2/Labs
mkdir exercises_pointers
cd exercises_pointers

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.


Pointers in C exercises — Basic Level

Exercise 1 — Copy and compare arrays

Write a C program with three functions that work with integer arrays using pointers:

  • copy_array(int *source, int *dest, int n) — copies n elements from source to dest
  • arrays_equal(int *a, int *b, int n) — returns 1 if all elements are equal, 0 otherwise
  • fill_array(int *arr, int n, int value) — fills all n elements with value
=== ARRAY COPY AND COMPARE ===

Original array:   10 20 30 40 50
After copy:       10 20 30 40 50
Arrays equal?:    Yes

After fill with 7: 7 7 7 7 7
Equal to original?: No

Copy of original:  10 20 30 40 50
Still equal?:      Yes

💡 Hints:

  • copy_array: for (int i = 0; i < n; i++) *(dest+i) = *(source+i);
  • arrays_equal: loop comparing *(a+i) with *(b+i) — return 0 at first mismatch
  • fill_array: loop setting *(arr+i) = value
  • Print arrays with a separate function that takes int *arr, int n

Exercise 2 — Count and replace

Write a C program with these pointer-based functions for integer arrays:

  • count_value(int *arr, int n, int target) — returns how many times target appears
  • count_greater(int *arr, int n, int threshold) — returns how many elements are greater than threshold
  • replace_value(int *arr, int n, int old_val, int new_val) — replaces all occurrences of old_val with new_val, returns count of replacements
  • clamp_array(int *arr, int n, int min, int max) — sets any element below min to min and above max to max
=== COUNT AND REPLACE ===

Array: 3 7 2 7 5 7 1 8 7 4

Count of 7:          4
Count above 5:       3
After replace 7→0:   3 0 2 0 5 0 1 8 0 4  (4 replacements)
After clamp [3,6]:   3 3 3 3 5 3 3 6 3 4

💡 Hints:

  • All functions take int *arr — walk with pointer arithmetic or array indexing
  • replace_value increments a counter each time it replaces and returns that count
  • clamp_array uses nested if: if element < min set to min, else if element > max set to max

Pointers in C exercises — Intermediate Level

Exercise 3 — String operations without string.h

Implement these string functions using only char pointers — without using any function from <string.h>:

  • my_strlen(const char *s) — returns string length (without counting \0)
  • my_strcpy(char *dest, const char *src) — copies src into dest
  • my_strcat(char *dest, const char *src) — appends src to end of dest
  • my_strcmp(const char *a, const char *b) — returns 0 if equal, negative if a < b, positive if a > b
  • my_contains(const char *haystack, char needle) — returns 1 if needle is in haystack
=== STRING FUNCTIONS ===

String 1: "Hello"
String 2: " World"

Length of s1:     5
Copy s2 to s3:    " World"
Concat s1+s2:     "Hello World"
Compare s1,s1:    0 (equal)
Compare s1,s2:    positive (H > space in ASCII)
Contains 'o':     Yes
Contains 'z':     No

💡 Hints:

  • my_strlen: walk p until *p == '\0', return p - s
  • my_strcpy: while ((*dest++ = *src++) != '\0'); — copy and advance simultaneously
  • my_strcat: first advance dest to its end, then copy src
  • my_strcmp: walk both pointers, return *a - *b at first difference or when one ends

Pointers in C exercises — Final Challenge

Exercise 4 — Integer stack with pointers

Implement a basic stack (LIFO — Last In First Out) using an integer array and a pointer to track the top. The stack must support push, pop, peek and display.

=== INTEGER STACK ===

Push 10 → Stack: 10
Push 20 → Stack: 10 20
Push 30 → Stack: 10 20 30
Push 40 → Stack: 10 20 30 40

Peek (top): 40
Size:       4

Pop → 40 removed. Stack: 10 20 30
Pop → 30 removed. Stack: 10 20
Pop → 20 removed. Stack: 10
Pop → 10 removed. Stack: (empty)
Pop on empty stack → Error: stack underflow

💡 Hints:

  • Use int data[MAX] for storage and int *top pointing to current top position
  • push: check if full, then *top = value; top++;
  • pop: check if empty, then top--; return *top; (or use a temp)
  • peek: return *(top-1) without moving top
  • is_empty: top == data (pointer equals start of array)
  • is_full: top == data + MAX
  • Pass the stack components as parameters: int *data, int **top, int max

Commented solutions

Solution Exercise 1

#include <stdio.h>

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

void copy_array(int *source, int *dest, int n) {
    for (int i = 0; i < n; i++)
        *(dest+i) = *(source+i);
}

int arrays_equal(int *a, int *b, int n) {
    for (int i = 0; i < n; i++)
        if (*(a+i) != *(b+i)) return 0;
    return 1;
}

void fill_array(int *arr, int n, int value) {
    for (int i = 0; i < n; i++)
        *(arr+i) = value;
}

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

    printf("=== ARRAY COPY AND COMPARE ===\n\n");

    printf("Original array:   ");
    print_array(original, n);

    copy_array(original, copy, n);
    printf("After copy:       ");
    print_array(copy, n);

    printf("Arrays equal?:    %s\n\n",
           arrays_equal(original, copy, n) ? "Yes" : "No");

    fill_array(copy, n, 7);
    printf("After fill with 7: ");
    print_array(copy, n);

    printf("Equal to original?: %s\n\n",
           arrays_equal(original, copy, n) ? "Yes" : "No");

    copy_array(original, copy, n);
    printf("Copy of original:  ");
    print_array(copy, n);
    printf("Still equal?:      %s\n",
           arrays_equal(original, copy, n) ? "Yes" : "No");

    return 0;
}

Solution Exercise 2

#include <stdio.h>

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

int count_value(int *arr, int n, int target) {
    int count = 0;
    for (int i = 0; i < n; i++)
        if (*(arr+i) == target) count++;
    return count;
}

int count_greater(int *arr, int n, int threshold) {
    int count = 0;
    for (int i = 0; i < n; i++)
        if (*(arr+i) > threshold) count++;
    return count;
}

int replace_value(int *arr, int n, int old_val, int new_val) {
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (*(arr+i) == old_val) {
            *(arr+i) = new_val;
            count++;
        }
    }
    return count;
}

void clamp_array(int *arr, int n, int min, int max) {
    for (int i = 0; i < n; i++) {
        if (*(arr+i) < min)      *(arr+i) = min;
        else if (*(arr+i) > max) *(arr+i) = max;
    }
}

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

    printf("=== COUNT AND REPLACE ===\n\n");
    printf("Array: ");
    print_array(arr, n);

    printf("Count of 7:       %d\n", count_value(arr, n, 7));
    printf("Count above 5:    %d\n", count_greater(arr, n, 5));

    int replaced = replace_value(arr, n, 7, 0);
    printf("After replace 7→0: ");
    print_array(arr, n);
    printf("(%d replacements)\n", replaced);

    clamp_array(arr, n, 3, 6);
    printf("After clamp [3,6]: ");
    print_array(arr, n);

    return 0;
}

Solution Exercise 3

#include <stdio.h>

int my_strlen(const char *s) {
    const char *p = s;
    while (*p != '\0') p++;
    return (int)(p - s);
}

void my_strcpy(char *dest, const char *src) {
    while ((*dest++ = *src++) != '\0');
}

void my_strcat(char *dest, const char *src) {
    while (*dest != '\0') dest++;    /* advance to end of dest */
    while ((*dest++ = *src++) != '\0');  /* copy src */
}

int my_strcmp(const char *a, const char *b) {
    while (*a != '\0' && *b != '\0' && *a == *b) {
        a++;
        b++;
    }
    return (unsigned char)*a - (unsigned char)*b;
}

int my_contains(const char *haystack, char needle) {
    while (*haystack != '\0') {
        if (*haystack == needle) return 1;
        haystack++;
    }
    return 0;
}

int main() {
    printf("=== STRING FUNCTIONS ===\n\n");

    char s1[50] = "Hello";
    char s2[50] = " World";
    char s3[50];
    char s4[100] = "Hello";

    printf("String 1: \"%s\"\n", s1);
    printf("String 2: \"%s\"\n\n", s2);

    printf("Length of s1:     %d\n", my_strlen(s1));

    my_strcpy(s3, s2);
    printf("Copy s2 to s3:    \"%s\"\n", s3);

    my_strcat(s4, s2);
    printf("Concat s1+s2:     \"%s\"\n", s4);

    printf("Compare s1,s1:    %d (%s)\n",
           my_strcmp(s1, s1),
           my_strcmp(s1, s1) == 0 ? "equal" : "not equal");

    int cmp = my_strcmp(s1, s2);
    printf("Compare s1,s2:    %s\n",
           cmp > 0 ? "positive (H > space in ASCII)" :
           cmp < 0 ? "negative" : "equal");

    printf("Contains 'o':     %s\n",
           my_contains(s1, 'o') ? "Yes" : "No");
    printf("Contains 'z':     %s\n",
           my_contains(s1, 'z') ? "Yes" : "No");

    return 0;
}

Solution Exercise 4

#include <stdio.h>

#define MAX 10

typedef struct {
    int data[MAX];
    int *top;       /* points to next empty slot */
} Stack;

void stack_init(Stack *s) {
    s->top = s->data;    /* top points to start — stack is empty */
}

int stack_is_empty(Stack *s) {
    return s->top == s->data;
}

int stack_is_full(Stack *s) {
    return s->top == s->data + MAX;
}

int stack_size(Stack *s) {
    return (int)(s->top - s->data);
}

int stack_push(Stack *s, int value) {
    if (stack_is_full(s)) {
        printf("Error: stack overflow\n");
        return 0;
    }
    *s->top = value;
    s->top++;
    return 1;
}

int stack_pop(Stack *s, int *value) {
    if (stack_is_empty(s)) {
        printf("Error: stack underflow\n");
        return 0;
    }
    s->top--;
    *value = *s->top;
    return 1;
}

int stack_peek(Stack *s, int *value) {
    if (stack_is_empty(s)) {
        printf("Error: stack is empty\n");
        return 0;
    }
    *value = *(s->top - 1);
    return 1;
}

void stack_print(Stack *s) {
    if (stack_is_empty(s)) {
        printf("(empty)");
        return;
    }
    int *p = s->data;
    while (p < s->top) {
        printf("%d ", *p);
        p++;
    }
}

int main() {
    Stack s;
    stack_init(&s);
    int value;

    printf("=== INTEGER STACK ===\n\n");

    int to_push[4] = {10, 20, 30, 40};
    for (int i = 0; i < 4; i++) {
        stack_push(&s, to_push[i]);
        printf("Push %d → Stack: ", to_push[i]);
        stack_print(&s);
        printf("\n");
    }

    stack_peek(&s, &value);
    printf("\nPeek (top): %d\n", value);
    printf("Size:       %d\n\n", stack_size(&s));

    while (!stack_is_empty(&s)) {
        stack_pop(&s, &value);
        printf("Pop → %d removed. Stack: ", value);
        stack_print(&s);
        printf("\n");
    }

    /* Test underflow */
    stack_pop(&s, &value);

    return 0;
}

Visualise with Python Tutor

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

#include <stdio.h>

void copy_array(int *src, int *dst, int n) {
    for (int i = 0; i < n; i++)
        *(dst + i) = *(src + i);
}

int main() {
    int a[3] = {10, 20, 30};
    int b[3];

    copy_array(a, b, 3);

    for (int i = 0; i < 3; i++)
        printf("b[%d] = %d\n", i, b[i]);

    return 0;
}

Step through copy_array carefully. When the function is called, src receives the address of a[0] and dst receives the address of b[0] — two separate arrows in memory. On each iteration *(src + i) follows the src arrow, steps i positions forward, and reads the value there. *(dst + i) follows the dst arrow and writes to that position. After the loop both a and b contain the same values but in completely different memory locations — they are genuinely independent copies. Change b[0] after the copy and watch that a[0] doesn’t change — that independence is the whole point of copy functions.


Cheat sheet — Pointers in C

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

/* DECLARING A POINTER */
int    *p;    /* pointer to int */
double *p;    /* pointer to double */
char   *p;    /* pointer to char (and strings) */

/* & — ADDRESS-OF OPERATOR */
int x = 5;
int *p = &x;   /* p stores the address of x */
printf("%p", &x);   /* print address — use %p */

/* * — TWO USES */
int *p;        /* in declaration: "p is a pointer to int" */
*p = 10;       /* as operator: "value AT address p" */
printf("%d", *p); /* dereference: read value at address */

/* THE COMPLETE PICTURE */
int x = 5;
int *p = &x;
/* x   → 5    (the value) */
/* &x  → 0x.. (the address) */
/* p   → 0x.. (p stores the same address as &x) */
/* *p  → 5    (value at address p — same as x) */

/* MODIFYING THROUGH POINTER */
*p = 20;       /* x is now 20 */

/* NULL — uninitialised pointer */
int *p = NULL;
if (p != NULL) { *p = 5; }   /* always check before use */
/* *p = 5 when p is NULL → segfault crash */

/* POINTER ARITHMETIC */
int arr[5] = {10,20,30,40,50};
int *p = arr;          /* p → arr[0] */
*(p+1)                 /* → 20 (arr[1]) */
*(p+i)                 /* → arr[i] */
p++                    /* advance by sizeof(int) = 4 bytes */
p < arr + 5            /* check: not past end of array */

/* ARRAYS AND POINTERS — EQUIVALENT */
arr[i]  ==  *(arr + i)     /* same thing */
arr     ==  &arr[0]        /* array name = address of first element */

/* PASS BY POINTER — modify original */
void double_val(int *p) { *p *= 2; }
double_val(&x);           /* x is modified */

/* ARRAYS TO FUNCTIONS — no & needed */
void process(int *arr, int n) { ... }
process(numbers, n);      /* array name already is a pointer */

/* MULTIPLE RETURN VALUES */
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 */

/* STRINGS AS CHAR POINTERS */
char s[] = "Hello";
char *p = s;
while (*p != '\0') {      /* walk until null terminator */
    printf("%c", *p);
    p++;
}

/* POINTER SUBTRACTION */
char *start = s;
char *end = s;
while (*end != '\0') end++;
int length = end - start;   /* number of elements between */

/* TWO-POINTER TECHNIQUE */
int *left  = arr;
int *right = arr + n - 1;
while (left < right) {
    /* swap *left and *right */
    int tmp = *left; *left = *right; *right = tmp;
    left++; right--;
}

/* CONST POINTER — read-only parameter */
void print_str(const char *s) {
    /* *s = 'X';  → compile error — const prevents modification */
    printf("%s", s);
}

/* COMMON ERRORS */
/* 1. Dereferencing NULL → segfault */
/* 2. Using uninitialised pointer */
/* 3. Forgetting & in function call: func(x) not func(&x) */
/* 4. Confusing p (address) with *p (value) */
/* 5. p++ moves sizeof(type) bytes, not 1 byte for int/double */

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

Similar Posts

Leave a Reply

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