Practice test for Midterm Part 1

Fifty minutes, four programs, written on a lab machine and uploaded to Brightspace. It counts for nothing and it is built to match Midterm Part 1.

Fifty minutes. It counts for nothing. Everything on Midterm Part 1 applies: open book and open notes, no AI, no collaboration, and you hand in by uploading to Brightspace — the assignment entry is called Practice test. Upload early and upload again; a program that does not compile is still worth uploading.

1. temps.c — five numbers, two answers

Read five integers with scanf. Print the largest of them, then their average as a number with a fraction.

No array. A loop and a few variables is the whole program — the five numbers do not need to be kept.

For the input 3 4 4 5 6 it prints:

largest 6
average 4.400000

Done when it prints those two lines for that input, and the right two lines for -2 -7 -1 -9 -3.

2. days.c — a function that returns a value

Write int days_in_month(int month): 31, 30 or 28 for months 1 to 12, with February as 28, and 0 for a month that does not exist. Then a main that prints the answer for months 1, 2, 4 and 13:

month 1 has 31 days
month 2 has 28 days
month 4 has 30 days
month 13 has 0 days

Done when it prints exactly that.

3. marks — one program in three files, and a Makefile

  • marks.h — an include guard, and prototypes for smallest and count_above. Nothing else.

  • marks.c — the two definitions, and no main. int smallest(int arr[], int n) is the smallest number in the array. int count_above(int arr[], int n, int limit) is how many of them are greater than limit.

  • main.c — main and nothing else. An array holding the five marks 73 91 58 84 66, and two lines:

    smallest 58
    above 80: 2
  • Makefile — builds a program called marks from the two .c files, and has a clean rule. Type it by hand, tab and all. Any Makefile that builds the program is a correct answer — with .o files or without.

Done when make builds it, ./marks prints those two lines, and make a second time in a row says there is nothing to do.

4. letters.c — how many times a letter appears

Read one word with scanf("%99s", word) into a char word[100], and print how many times the letter e appears in it. Walk to the '\0' yourself — no strlen.

word: seventeen
e appears 4 times

Done when it prints that for seventeen, and e appears 0 times for rhythm.

Reference solutions

Published after the test. Each is one correct answer, not the only one — yours may look different and still be right. Every one of these was compiled with gcc -Wall and run on the inputs above. Each function carries the design recipe’s one-line comment saying what it computes, above its prototype where it has one.

1. temps.c

#include <stdio.h>

#define COUNT 5

int main() {
    int largest;
    scanf("%d", &largest);
    int sum = largest;

    for (int i = 1; i < COUNT; i++) {
        int t;
        scanf("%d", &t);
        sum += t;
        if (t > largest) {
            largest = t;
        }
    }
    printf("largest %d\n", largest);
    printf("average %f\n", (double) sum / COUNT);
}

largest starts as the first number, read before the loop, so it is never compared with anything before it has a value. (double) sum / COUNT is what keeps the fraction; sum / COUNT throws it away before the division happens. And the five is written once, as COUNT, so that changing it is one edit and not three.

2. days.c

#include <stdio.h>

// returns the days in month, 1 to 12, with February as 28; 0 for any other month
int days_in_month(int month) {
    if (month == 2) {
        return 28;
    } else if (month == 4 || month == 6 || month == 9 || month == 11) {
        return 30;
    } else if (month >= 1 && month <= 12) {
        return 31;
    } else {
        return 0;
    }
}

int main() {
    printf("month 1 has %d days\n", days_in_month(1));
    printf("month 2 has %d days\n", days_in_month(2));
    printf("month 4 has %d days\n", days_in_month(4));
    printf("month 13 has %d days\n", days_in_month(13));
}

Each || joins a complete comparison. month == 4 || 6 is always true, because 6 on its own is.

3. marks

marks.h

#ifndef MARKS_H
#define MARKS_H

// returns the smallest of the n values in arr
int smallest(int arr[], int n);

// returns how many of the n values in arr are greater than limit
int count_above(int arr[], int n, int limit);

#endif

marks.c

#include "marks.h"

int smallest(int arr[], int n) {
    int best = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] < best) {
            best = arr[i];
        }
    }
    return best;
}

int count_above(int arr[], int n, int limit) {
    int count = 0;
    for (int i = 0; i < n; i++) {
        if (arr[i] > limit) {
            count++;
        }
    }
    return count;
}

main.c

#include <stdio.h>
#include "marks.h"

#define SIZE 5

int main() {
    int marks[SIZE] = {73, 91, 58, 84, 66};

    printf("smallest %d\n", smallest(marks, SIZE));
    printf("above 80: %d\n", count_above(marks, SIZE, 80));
}

Makefile — the whitespace before each command is one tab.

marks: main.o marks.o
	gcc -Wall -o marks main.o marks.o

main.o: main.c marks.h
	gcc -Wall -c main.c

marks.o: marks.c marks.h
	gcc -Wall -c marks.c

clean:
	rm -f marks main.o marks.o

The one-rule form is equally right: marks: main.c marks.c marks.h with gcc -Wall -o marks main.c marks.c under it, and the same clean.

4. letters.c

#include <stdio.h>

int main() {
    char word[100];
    int count = 0;

    printf("word: ");
    scanf("%99s", word);
    for (int i = 0; word[i] != '\0'; i++) {
        if (word[i] == 'e') {
            count++;
        }
    }
    printf("e appears %d times\n", count);
}

%99s, with no & in front of word: an array’s name already says where it is.