Solutions: Lecture 4 In-Class Exercises¶
Instructor key for exercises.md. Keep separate from the student
handout.
Part A - Integer arrays¶
Exercise A1 - Largest and smallest¶
#include <stdio.h>
int main(void) {
int a[] = {42, 17, 99, 3, 56, 8};
int n = 6; /* six values, so n is 6 */
int min = a[0];
int max = a[0];
for (int i = 1; i < n; i++) {
if (a[i] < min) {
min = a[i];
}
if (a[i] > max) {
max = a[i];
}
}
printf("largest: %d\n", max);
printf("smallest: %d\n", min);
return 0;
}
- Seed from
a[0], not0. If you startmax = 0and every value is negative, you wrongly report0as the largest. Seeding from an actual element avoids assuming anything about the data. - Loop from
i = 1since element0is already accounted for. - Stretch (index of the max): keep an
int max_idx = 0;and setmax_idx = i;in the same branch that updatesmax.
Exercise A2 - A sum function (and an average)¶
#include <stdio.h>
int sum(int a[], int n) {
int total = 0;
for (int i = 0; i < n; i++) {
total += a[i];
}
return total;
}
double average(int a[], int n) {
return (double) sum(a, n) / n; /* cast BEFORE dividing */
}
int main(void) {
int a[] = {42, 17, 99, 3, 56, 8};
int n = 6; /* six values, so n is 6 */
printf("sum: %d\n", sum(a, n));
printf("average: %.2f\n", average(a, n));
return 0;
}
- The cast must happen before the division.
sum(a, n) / nis integer division (it would print37.00);(double) sum(a, n) / ndoes real division. averagereusessum- no second loop needed.nis passed explicitly because inside these functionsais just a reference to where the array starts - the count is not carried with it, so the caller has to supply it.
Part B - Strings¶
Exercise B1 - Count uppercase and lowercase¶
#include <stdio.h>
int main(void) {
char word[256];
printf("Enter a word: ");
scanf("%s", word);
int upper = 0, lower = 0;
for (int i = 0; word[i] != '\0'; i++) {
char c = word[i];
if (c >= 'A' && c <= 'Z') {
upper++;
} else if (c >= 'a' && c <= 'z') {
lower++;
}
}
printf("uppercase: %d\n", upper);
printf("lowercase: %d\n", lower);
return 0;
}
- The loop condition
word[i] != '\0'is the standard "walk to the terminator."scanf("%s", word)reads one whitespace-delimited word and writes the'\0'for you, so there is no stray newline to worry about. - Stretch (digits and other): add
else if (c >= '0' && c <= '9') digits++;and anelsefor everything else, then checkupper + lower + digits + other == length.
Exercise B2 - Redact the letters (modify in place)¶
#include <stdio.h>
int main(void) {
char word[256];
printf("Enter a word: ");
scanf("%s", word);
for (int i = 0; word[i] != '\0'; i++) {
char c = word[i];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
word[i] = '#';
}
}
printf("redacted: %s\n", word);
return 0;
}
- The whole exercise is the assignment
word[i] = '#';- you are changing the array in place as you walk it, exactly the move HW1's case conversion and cipher need. Here the per-character decision is deliberately trivial so the mechanics are the only new thing. - The
||joins the two case ranges so both upper and lower letters are caught. - Non-letters fall through with no
else, so digits and punctuation are left exactly as typed.
Stretch¶
1. Letter-frequency histogram¶
#include <stdio.h>
int main(void) {
char word[256];
printf("Enter a word: ");
scanf("%s", word);
int counts[26] = {0};
for (int i = 0; word[i] != '\0'; i++) {
char c = word[i];
if (c >= 'A' && c <= 'Z') {
c = c - 'A' + 'a'; /* fold case so 'A' and 'a' share a bin */
}
if (c >= 'a' && c <= 'z') {
counts[c - 'a']++; /* the letter itself is the index */
}
}
for (int k = 0; k < 26; k++) {
if (counts[k] > 0) {
printf("%c: %d\n", 'a' + k, counts[k]);
}
}
return 0;
}
counts[c - 'a']is the key idea:c - 'a'turns'a'..'z'into0..25, a valid index. That same letter-to-0..25mapping is what the HW1 cipher does before it shifts and wraps with% 26.- Folding uppercase to lowercase first means
'A'and'a'land in the same bin. - Printing back uses the inverse map,
'a' + k, to recover the letter from its index.
2. Find a character¶
int index_of(char s[], char target) {
for (int i = 0; s[i] != '\0'; i++) {
if (s[i] == target) {
return i; /* first match wins */
}
}
return -1; /* walked the whole string, never found it */
}
- A plain walk that returns early on the first hit; falling off the loop means
it was not there, so we return the sentinel
-1. This early-return-or-sentinel shape shows up in lots of string code.
3. Most common letter¶
/* assumes counts[26] has already been filled as in stretch 1 */
int best = 0;
for (int k = 1; k < 26; k++) {
if (counts[k] > counts[best]) {
best = k;
}
}
printf("most common: %c (%d)\n", 'a' + best, counts[best]);
- This is exercise A1's maximum scan applied to the histogram: track the index of
the largest count seen so far, starting from
best = 0and checking fromk = 1. Combining the string walk (to fillcounts) with the array scan (to find the max) is the kind of two-step build HW1 problems ask for.