Class 12 — Thursday, October 1
1 A calculator, in stages
For anyone with nothing to correct, and anyone who finishes. In pairs; swap who types at every Done when.
Your calculator reads one expression with no spaces, such as 12+34, and walks it to its '\0', as stars.c did. This starter prints each character on its own line:
#include <stdio.h>
#define SIZE 100
int main() {
char line[SIZE];
scanf("%99s", line);
for (int i = 0; line[i] != '\0'; i++) {
char c = line[i];
printf("%c\n", c);
}
}One new fact: a character that is a digit becomes its number with c - '0', so '7' - '0' is 7.
1.1 Two numbers
12+34 prints 46, and 7-10 prints -3. Build each number one digit at a time: multiply what you have so far by 10, then add the new digit.
Done when both print as shown.
1.2 Any length
12+34-5+100 prints 141. Keep a running total, and apply each operator when you reach the next one.
Done when it prints 141.
1.3 Times and divide
Add * and /, still working from left to right: 2+3*4 prints 20, and 100/7*7 prints 98.
Done when both print as shown, and you can say why the second is not 100.
1.4 Precedence
Now make * and / happen before + and -: 2+3*4 prints 14, 10-2*3 prints 4, and 100/7*7 still prints 98. Keep two numbers: the total of the finished parts, and the part you are still multiplying.
Done when all three print as shown.
1.5 Break it
Try 7/0, 99999*99999 and 12+. For each one, add a comment line to your file: what happened, and why.
Done when the file has all three comments.
1.6 Fix what you broke
Print cannot divide by zero for 7/0, and missing number for 12+, instead of crashing or guessing.
Done when both print those words.
1.7 Many expressions, from a file
scanf returns how many things it read, so while (scanf("%99s", line) == 1) runs once for each expression until there are none left. Put five expressions in exprs.txt, one per line, and run:
./calc < exprs.txtDone when one run prints all five answers.
2 The swap that works
2.1 The one that did nothing
From A3. Predict what it prints, then run it.
#include <stdio.h>
#include <assert.h>
void swap(int a, int b) {
int t = a;
a = b;
b = t;
}
int main() {
int x = 3;
int y = 8;
printf("before: x = %d, y = %d\n", x, y);
swap(x, y);
printf("after: x = %d, y = %d\n", x, y);
assert(x == 8);
assert(y == 3);
}2.2 Give it the addresses
#include <stdio.h>
#include <assert.h>
// swaps the two variables that a and b point to
void swap(int * a, int * b) {
int t = *a;
*a = *b;
*b = t;
}
int main() {
int x = 3;
int y = 8;
printf("before: x = %d, y = %d\n", x, y);
swap(&x, &y);
printf("after: x = %d, y = %d\n", x, y);
assert(x == 8);
assert(y == 3);
}Predict: what does the after: line print now?
&xis the address ofx: wherexlives in memory.int * amakesaa pointer: a variable that holds the address of anint.*afollows that address: it is the variableapoints to.
Every scanf("%d", &n) you have written used the same &: scanf has to know where n lives in order to put the number there.
2.3 Where things live
#include <stdio.h>
int main() {
int x = 3;
int * p = &x;
printf("x is %d, and lives at %p\n", x, &x);
printf("p holds %p, and *p is %d\n", p, *p);
}Predict: do the two lines print the same address?
2.4 Without the &
Change the call in the working swap to swap(x, y);. Predict first: does it compile?
3 Pointers, in pairs
In pairs; swap who types at every Done when. Every function gets the design recipe’s one-line comment, and every test at least one assert of your own.
3.1 twice
Write void twice(int * p), which doubles the variable that p points to. Start from int n = 21;, call twice(&n);, and assert(n == 42);.
Done when the assert passes.
3.2 shift
Write void shift(int * a, int * b, int * c), which moves each value one variable to the right, and the last one round to the first:
int main() {
int x = 1;
int y = 2;
int z = 3;
shift(&x, &y, &z);
assert(x == 3);
assert(y == 1);
assert(z == 2);
}Done when these pass, and so do your own asserts that three shifts bring all three values back to where they started.
3.3 One step of Fibonacci
Write void fib_step(int * a, int * b), which turns the pair a, b into b, a + b. From 0, 1, one step gives 1, 1, and ten steps give 55, 89:
#define STEPS 10
int main() {
int a = 0;
int b = 1;
for (int i = 0; i < STEPS; i++) {
fib_step(&a, &b);
}
assert(a == 55);
assert(b == 89);
}Done when both pass.
3.4 A swap with no spare variable
This swap needs no third variable:
// swaps the two variables that a and b point to, without a third variable
void swap2(int * a, int * b) {
*a = *a + *b;
*b = *a - *b;
*a = *a - *b;
}Check that it swaps x and y. Then call swap2(&x, &x);. Predict first: what is x afterwards? Then make the same call with the swap from section 2.2.
Done when you can say why the two swaps disagree.
3.5 The address of the bigger one
A function can return an address too. Write int * bigger(int * a, int * b), which returns the address of whichever variable holds the larger value. Then this line sets the larger of x and y to zero, whichever one it is:
int main() {
int x = 4;
int y = 9;
*bigger(&x, &y) = 0;
assert(x == 4);
assert(y == 0);
}Done when it passes, and still does with the values of x and y the other way round.
4 Before you leave
- A5 is out, due Wednesday, October 7.
- The reading for Tuesday is [DIS] 2.2 — C’s Pointer Variables and [DIS] 2.3 — Pointers and Functions. Quiz 5 on it opens Tuesday’s class.
- The Closing Journal: its prompt is in the announcements on Brightspace.