Skip to content

Solutions: Lecture 5 In-Class Exercises

Solutions to the Lecture 5 in-class exercises. Try each exercise yourself before reading these.


Part A - Read the pointers (pen and paper)

Exercise A1 - Trace the boxes and arrows

int x = 10;
int *p = &x;
*p = *p + 5;
      +------+            +------+
  x:  |  15  | <--------- |  p   |
      +------+            +------+
      addr 2000           holds 2000
  1. p holds a number: the address of x (here 2000). It does not hold 10; it holds where the 10 lives.
  2. Just before the third line, *p is 10 - follow p to x and read it.
  3. *p = *p + 5; reads 10, adds 5, and writes 15 back through p into x. So x is 15, and *p is 15 - they are two names for the same box.
  4. p prints 2000 (the address of x). &p prints something different: the address of the p box itself. p and &p are not the same - one is where x is, the other is where p is.

  5. Stretch: after int y = 7; p = &y;, the arrow now points at y. x is untouched (still 15) - reassigning p only moves the arrow, it does not copy values. *p is now 7.


Part B - Pointers at the keyboard

Exercise B1 - Sum an array with a walking pointer

#include <stdio.h>

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

    int total = 0;
    for (int *p = a; p < a + n; p++) {
        total += *p;
    }

    printf("sum = %d\n", total);
    return 0;
}
sum = 150
  • int *p = a; starts the pointer at a[0] - the array name decays to that address, so no & is needed.
  • p < a + n stops the loop exactly at the one-past-the-end address. We compare against it but never write *p there.
  • This is the index loop for (int i = 0; i < n; i++) total += a[i]; with the address moving instead of the index. *p here is *(a + i) there.
  • Stretch (addresses): printf("%p: %d\n", (void *) p, *p); inside the loop prints each slot's address; they rise by sizeof(int) (typically 4) each step, which is why p++ lands on the next element.

Exercise B2 - Swap through addresses

#include <stdio.h>

void swap(int *a, int *b) {
    int t = *a;
    *a = *b;
    *b = t;
}

int main(void) {
    int x = 3, y = 7;
    printf("before: x = %d, y = %d\n", x, y);
    swap(&x, &y);
    printf("after:  x = %d, y = %d\n", x, y);
    return 0;
}
before: x = 3, y = 7
after:  x = 7, y = 3
  • Every read and write inside swap goes through a *, so it lands on the caller's x and y, not on local copies. The temporary t is a plain int holding one value mid-swap.
  • The bug to avoid - swapping the pointers themselves:
void swap_wrong(int *a, int *b) {
    int *t = a; a = b; b = t;   /* shuffles the local copies of the addresses */
}

This rearranges swap's private pointer variables and returns; x and y never move. The fix is to operate on *a and *b, the things pointed at. - Stretch (swap_bad): a version taking int a, int b swaps its own copies and returns, so x and y are unchanged - C passed the values, not the variables.

Exercise B3 - Two results with out-parameters

#include <stdio.h>

void divide(int a, int b, int *quotient, int *remainder) {
    *quotient = a / b;
    *remainder = a % b;
}

int main(void) {
    int q, r;
    divide(17, 5, &q, &r);
    printf("17 / 5 = %d remainder %d\n", q, r);
    return 0;
}
17 / 5 = 3 remainder 2
  • The caller owns q and r; it passes their addresses so divide can fill them in. After the call, q and r hold the results.
  • This is the standard C way to return more than one value, since return hands back only one. scanf works the same way: a status comes back through return, your data through the pointers.
  • Stretch (the check): q * b + r == a should hold for every pair, e.g. 3 * 5 + 2 == 17. It is the definition of integer division and remainder.

Stretch

minmax with out-parameters

#include <stdio.h>

void minmax(const int *a, int n, int *lo, int *hi) {
    *lo = a[0];
    *hi = a[0];
    for (int i = 1; i < n; i++) {
        if (a[i] < *lo) {
            *lo = a[i];
        }
        if (a[i] > *hi) {
            *hi = a[i];
        }
    }
}

int main(void) {
    int a[] = {42, 17, 99, 3, 56, 8};
    int n = 6;

    int lo, hi;
    minmax(a, n, &lo, &hi);
    printf("lo = %d, hi = %d\n", lo, hi);
    return 0;
}
lo = 3, hi = 99
  • Both results travel back through *lo and *hi, so one pass returns two values - something a single return cannot do.
  • Seed *lo and *hi from a[0], then start the loop at i = 1. Seeding from an actual element (not 0) keeps it correct for all-negative arrays.
  • const int *a says minmax only reads the array. If you accidentally wrote a[i] = ..., the compiler would reject it - a cheap guard worth using whenever a function should not modify its input.