Coding Exercises

I think that many teachers (whether you tutor, TA, or lecture) can relate to the problem of coming up with appropriate exercises on the spot. After reading another post 1 by another TA, I thought I’d put together a list of examples with code examples. Each exercise has an explanation, and examples are given in C and Python.

I will update this list of projects when I think of some more ideas, but please leave any suggestions (or corrections) in the comments!

Feel free to use these materials as you wish. I only ask that you provide attribution, and link back to this page.

Table of Contents

Getting Started

Hello World!

Originally attributed to Brian Kernighan (one of the creators of the “C” language) when he worked at Bell Labs, pretty much every programmer starts off with this infamous program1.

#include <stdio.h>

int main() {
    printf("hello, world\n");
}
print("hello, world")

User Input

Important for a wide range of applications, most programs need user input to make them useful, so it makes sense that learning this early on is important.

#include <stdio.h>
#define MAX_SIZE 100

int main() {
    char name[MAX_SIZE];
    printf("What is your name? ");
    fgets(name, MAX_SIZE, stdin);
    printf("Hello %s", name);
}
name = input("What is your name? ")
print("Hello", name)

FizzBuzz

Based on a classic playground game, count up to a specific number, substituting multiples of 3 with “Fizz”, multiples of 5 with “Buzz”, and multiples of both with “FizzBuzz”.

for (int n = 0; n < 100; n++) {
    if (n % 5) == 0 && (n % 3) == 0 {
        printf("FizzBuzz\n");
    } else if (n % 5) == 0 {
        printf("Fizz\n");
    } else if (n % 3) == 0 {
        printf("Buzz\n");
    } else {
        printf("%d\n", n);
    }
}
for n in range(100):
    if (n % 5) == 0 and (n % 3) == 0:
        print("FizzBuzz")
    elif (n % 5) == 0:
        print("Fizz")
    elif (n % 3) == 0:
        print("Buzz")
    else:
        print(n)

Command Line Arguments

It can be really handy to get the command-line arguments of a program, so start off by first reading them and printing them out. Once you can do this, you can start to use them as useful, efficient user input.

#include <stdio.h>

int main(int argc, char** argv) {
    for (int i = 0; i < argc; i++) {
        printf("%s\n", argv[i]);
    }

    // You can also get specific options with...
    // getopt(int argc, char *const argv[], const char *optstring)
}
import sys
print(sys.argv)
print(len(sys.argv)) # Equivalent to argc
# Python provides a similar function: getopt.getopt(args, options, [long_options])

You can read more here:

File I/O

Reading to and writing from files is really crucial for a wide variety of problems, whether you are making some kind of file editor or using a SQLite Database.

#include <stdio.h>

int main() {
    // Reading files
    FILE* f = fopen("my_file.txt", "r");
    char c;
    do {
        c = fgetc(f);
        // This reads one character at a time (other methods are available)
        printf("%c", c);

    } while (c != EOF);
    fclose(f);

    // Writing to files
    FILE* f = fopen("my_file.txt", "w");
    const char* txt = "Some cool text to write...";
    fprintf(f, "You can use fprintf just like printf, writing strings and values (%d)\n", 37);
    // Again, other options are available for writing to files...
    fclose(f);
}
# Reading files
f = open("my_file.txt")
txt = f.read()
print(txt)
f.close()

# Reading files (Another Solution)
with open("my_file.txt") as f:
    txt = f.read()
    print(txt)

# Writing to files
txt = "Hello File!"
with open("my_file.txt", "w") as f:
    f.write(txt)

Intermediate Exercises

Bubble Sort

#include <stdio.h>

void sort(int a[], const int len) {
    int tmp;
    for (int i = 0; i < len-1; i++) {
        for (int j = i+1; j < len; j++) {
            if (a[i] > a[j]) { // Use < to sort descending instead
                // Swap
                tmp = a[i];
                a[i] = a[j];
                a[j] = tmp;
            }
        }
    }
}

void print_array(const int a[], const int len) {
    for (int i = 0; i < len; i++)
        printf("%d ", a[i]);
    printf("\n");
}

int main() {
    int arr[] = {3, -28, 634, 30, -32}, len = 5;
    printf("Unsorted: ");
    print_array(arr, len);

    sort(arr, len);
    printf("Sorted: ");
    print_array(arr, len);
}

Adapted from the pseudocode on includehelp.com

def sort(a):
    for i in range(len(a)):
        for j in range(i+1, len(a)):
            if a[i] > a[j]:             # Use < to sort descending instead
                a[i], a[j] = a[j], a[i] # Swap

arr = [3, -28, 634, 30, -32]
print(arr)

sort(arr)
print(arr)

Anagram

Write a function that can check whether two strings are anagrams of each other. As a bonus, think about how this could be optimised using techniques like dynamic programming.

#include <stdbool.h>
#include <string.h>
#include <malloc.h>

/** 
 * Sort a string's characters in alphabetical order
 * I use the bubble sort algorithm,
 * but you can use your favourite algorithm instead!
 **/
char* sort_string(const char* s) {
    const int n = strlen(s);
    char* sorted = malloc(sizeof(s));
    strcpy(sorted, s);
    char tmp;

    for (int i = 0; i < n-1; i++) {
        for (int j = i+1; j < n; j++) {
            if (sorted[i] > sorted[j]) {
                // Swap
                tmp = sorted[i];
                sorted[i] = sorted[j];
                sorted[j] = tmp;
            }
        }
    }

    return sorted;
}

/**
 * Returns 1 (true) if the strings are anagrams of each other
 * Returns 0 (false) if they are not
 **/
bool anagram(const char* s1, const char* s2) {
    if (strlen(s1) != strlen(s2)) {
        return false;
    }
    return strcmp(sort_string(s1), sort_string(s2)) == 0;
}

int main() {
    anagram("test", "tset");   // 1
    anagram("test", "test");   // 1
    anagram("steve", "brian"); // 0
    anagram("super", "upres"); // 1
}
def anagram(s1, s2):
    if len(s1) != len(s2):
        return False
    s1 = ''.join(sorted(s1))
    return s1 == ''.join(sorted(s2))

anagram("test", "tset")   # True
anagram("test", "test")   # True
anagram("steve", "brian") # False
anagram("super", "upres") # True

Chess Board

Chessboard (Photo from [Chase Clark](https://unsplash.com/@chaseelliottclark?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText))
Chessboard (Photo from Chase Clark)

Construct a chessboard, looking something like that shown in the figure above. You could produce output like this:

White Black White Black White Black White Black
Black White Black White Black White Black White
White Black White Black White Black White Black
Black White Black White Black White Black White
White Black White Black White Black White Black
Black White Black White Black White Black White
White Black White Black White Black White Black
Black White Black White Black White Black White

The following solutions just focus on producing the above output. However, you could modify them to produce a data structure that contains the chessboard.

#include <stdio.h>
#include <stdbool.h>

#define COLS 8
#define ROWS 8

int main() {
    char* colours[] = {"White", "Black"};
    bool alt = false;
    for (int i = 0; i < COLS*ROWS; i++) {
        if (i != 0 && i % COLS == 0) {
            printf("\n");
            alt = !alt;
        }
        printf("%s ", colours[alt ? 1-(i%2) : i%2]);
    }
}
COLS = 8
ROWS = 8

def print_board():
    colours = ["White", "Black"]
    alt = False
    for i in range(COLS*ROWS):
        if i != 0 and i % COLS == 0:
            print()
            alt = not alt
        print(colours[1-(i%2) if alt else i%2], end=" ")

print_board()

Pig Latin Translator

Pig Latin is produced by adding a fabricated suffix and reconstructing the pieces of English words. You can translate from English to Pig Latin by taking the first letter of each word, moving it to the end of the word and appending the suffix “ay”.

For example “Pig Latin is pretty cool” in English, would become “Igpay atinlay siay rettypay oolcay”.

def translate_english(s):
    a = []
    for word in s.split(" "):
        a.append(pl_w(word).lower())
    return " ".join(a)

def translate_piglatin(s):
    return " ".join([en_w(word).lower() for word in s.split(" ")])

def pl_w(s):
    return s[1:] + s[0] + "ay"

def en_w(s):
    return s[-3] + s[:-3]

def main():
    en = "Pig Latin is pretty cool"

    # Translate English to Pig Latin
    pl = translate_english(en)
    print(en)
    print(pl)

    # Translate Pig Latin to English
    print(translate_piglatin(pl))

if __name__ == "__main__":
    main()

Logic Problems

Wolf, Sheep, Cabbage

A classic river crossing problem 2. A farmer has bought a wolf, a sheep and a cabbage from a market on one side of a river, and needs to take them over to the other side. However, he can only take one at a time, and if the wolf is left alone with the sheep, or the sheep with the cabbage, they will be eaten.

You can solve the problem interactively on Coolmath Games.

Solution

  1. Take the sheep over
  2. Return
  3. Take the wolf or cabbage over
  4. Return with the sheep
  5. Take the cabbage or wolf over
  6. Return
  7. Take sheep over
Timothy Clark
Timothy Clark
Software Engineer

Software Engineer and Writer supporting early careers in tech.

comments powered by Disqus

Related