C Exercises

Practise what you've learned. Type the missing piece into each highlighted gap and press Check. Further down are programming challenges with editors and model solutions — copy them to compile and run locally.

Fill in the blanks

Basics

Include the header that declares printf.

#include <>

Declare the entry point of a program that takes no arguments.

int (void) {

Print an int followed by a newline.

printf("\n", count);

Print a double with two decimal places.

printf("%\n", price);

Print a size_t value.

printf("%\n", sizeof(int));

Read a double with scanf.

scanf("", &weight);

Get a fractional result from two ints.

double avg = () total / count;

Get the remainder of a division.

int r = 17  5;

Turn on bit 3 in flags.

flags  1u << 3;

Use exact-width integer types.

#include <>

Control flow and functions

Leave a switch case.

case 'q':
    running = 0;
    ;

A loop whose body always runs at least once.

 {
    ask();
} while (!valid);

Skip to the next iteration of a loop.

if (value < 0) ;

Declare a function before it's defined (a prototype).

int square(int n)

Keep a local variable's value between calls.

 int calls = 0;

Arrays and strings

Number of elements in an array.

size_t n = sizeof values / ;

The character that ends every C string.

buffer[len] = '';

Length of a string, not counting the terminator.

size_t len = (name);

Compare two strings by their contents.

if ((a, b) == 0) puts("same");

Read a whole line safely.

(line, sizeof line, stdin);

Format text into an array without overflowing it.

(label, sizeof label, "Order #%d", id);

Test whether a character is a digit.

if (((unsigned char) c)) digits++;

Pointers and memory

Store the address of score in a pointer.

int *p = score;

Change the value a pointer points to.

p = 100;

A pointer that points to nothing.

int *p = ;

Promise that a function won't modify the string it receives.

size_t count_spaces( char *s);

Allocate an array of n doubles on the heap.

double *data = (n * sizeof *data);

Release memory you allocated.

(data);

Allocate memory that starts out zeroed.

int *counts = (26, sizeof *counts);

Grow an allocation (using a temporary pointer).

int *grown = (items, new_cap * sizeof *items);

Structures and files

Access a member through a pointer to a struct.

pscore = 90;

Give a struct type a shorter name.

 struct { double x, y; } Point;

Sort an array with the standard library.

(scores, n, sizeof scores[0], compare_ints);

Open a file for appending.

FILE *log = fopen("app.log", "");

Close a file when you're done.

(log);

Print an error message with the system's reason.

("settings.ini");

Prevent a header from being included twice.

# STATS_H
#define STATS_H
/* ... */
#endif

Make a function private to its source file.

 int helper(int x);

Programming challenges

1. FizzBuzz

Print the numbers 1 to 15, but "Fizz" for multiples of 3, "Buzz" for multiples of 5 and "FizzBuzz" for both.

Try it yourself · main.c
Edit the code, copy it into main.c, then compile and run it with cc -std=c17 -Wall main.c -o main && ./main. How to set up a C compiler
Show a model solution
C
#include <stdio.h>

int main(void) {
    for (int i = 1; i <= 15; i++) {
        if (i % 15 == 0) printf("FizzBuzz ");
        else if (i % 3 == 0) printf("Fizz ");
        else if (i % 5 == 0) printf("Buzz ");
        else printf("%d ", i);
    }
    printf("\n");
    return 0;
}
Output
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz

2. Letter frequencies

Count how often each letter appears in a sentence, ignoring case, and print the letters that appear at least twice.

Try it yourself · main.c
Edit the code, copy it into main.c, then compile and run it with cc -std=c17 -Wall main.c -o main && ./main. How to set up a C compiler
Show a model solution
C
#include <stdio.h>
#include <ctype.h>

int main(void) {
    const char *text = "The quick brown fox jumps over the lazy dog";
    int counts[26] = { 0 };
    for (const char *p = text; *p; p++) {
        unsigned char c = *p;
        if (isalpha(c)) counts[tolower(c) - 'a']++;
    }
    for (int i = 0; i < 26; i++) {
        if (counts[i] >= 2) printf("%c: %d\n", 'a' + i, counts[i]);
    }
    return 0;
}
Output
e: 3
h: 2
o: 4
r: 2
t: 2
u: 2

3. Reverse the words

Write a function that reverses the order of the words in a string in place: "one two three" becomes "three two one". Hint: reverse the whole string, then reverse each word.

Try it yourself · main.c
Edit the code, copy it into main.c, then compile and run it with cc -std=c17 -Wall main.c -o main && ./main. How to set up a C compiler
Show a model solution
C
#include <stdio.h>
#include <string.h>

static void reverse_range(char *start, char *end) {   // end is exclusive
    while (start < --end) {
        char t = *start;
        *start++ = *end;
        *end = t;
    }
}

void reverse_words(char *s) {
    size_t len = strlen(s);
    reverse_range(s, s + len);
    char *word = s;
    for (char *p = s; ; p++) {
        if (*p == ' ' || *p == '\0') {
            reverse_range(word, p);
            if (*p == '\0') break;
            word = p + 1;
        }
    }
}

int main(void) {
    char sentence[] = "pointers are not that scary";
    reverse_words(sentence);
    printf("%s\n", sentence);
    return 0;
}
Output
scary that not are pointers

4. A dynamic stack

Implement a stack of int that grows with realloc, with push, pop and free functions. Use it to check whether brackets in a string are balanced.

Try it yourself · main.c
Edit the code, copy it into main.c, then compile and run it with cc -std=c17 -Wall main.c -o main && ./main. How to set up a C compiler
Show a model solution
C
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct {
    int *items;
    size_t count, capacity;
} Stack;

static bool push(Stack *s, int v) {
    if (s->count == s->capacity) {
        size_t cap = s->capacity ? s->capacity * 2 : 8;
        int *grown = realloc(s->items, cap * sizeof *grown);
        if (grown == NULL) return false;
        s->items = grown;
        s->capacity = cap;
    }
    s->items[s->count++] = v;
    return true;
}

static bool pop(Stack *s, int *out) {
    if (s->count == 0) return false;
    *out = s->items[--s->count];
    return true;
}

static void stack_free(Stack *s) {
    free(s->items);
    *s = (Stack) { 0 };
}

static bool balanced(const char *text) {
    Stack s = { 0 };
    bool ok = true;
    for (const char *p = text; *p && ok; p++) {
        int open;
        switch (*p) {
            case '(': case '[': case '{':
                ok = push(&s, *p);
                break;
            case ')': ok = pop(&s, &open) && open == '('; break;
            case ']': ok = pop(&s, &open) && open == '['; break;
            case '}': ok = pop(&s, &open) && open == '{'; break;
        }
    }
    ok = ok && s.count == 0;
    stack_free(&s);
    return ok;
}

int main(void) {
    const char *tests[] = { "{[()()]}", "([)]", "((", "f(a[1], {b})" };
    for (int i = 0; i < 4; i++) {
        printf("%-14s %s\n", tests[i], balanced(tests[i]) ? "balanced" : "not balanced");
    }
    return 0;
}
Output
{[()()]}       balanced
([)]           not balanced
((             not balanced
f(a[1], {b})   balanced

5. Word count from a file

Read a text file and print its number of lines, words and characters, like the Unix wc command.

TXT notes.txt
Buy milk
Call the plumber about the leak
Finish the C course
Try it yourself · main.c
Edit the code, copy it into main.c, then compile and run it with cc -std=c17 -Wall main.c -o main && ./main. How to set up a C compiler
Show a model solution
C
#include <stdio.h>
#include <ctype.h>

int main(void) {
    FILE *f = fopen("notes.txt", "r");
    if (f == NULL) {
        perror("notes.txt");
        return 1;
    }
    long lines = 0, words = 0, chars = 0;
    int in_word = 0, c;
    while ((c = fgetc(f)) != EOF) {
        chars++;
        if (c == '\n') lines++;
        if (isspace(c)) {
            in_word = 0;
        } else if (!in_word) {
            in_word = 1;
            words++;
        }
    }
    fclose(f);
    printf("%ld lines, %ld words, %ld characters\n", lines, words, chars);
    return 0;
}
Output
3 lines, 12 words, 61 characters