Loops (While)
COP-3223H
Table of Contents
Recall: exponent on desktop calculator
\(x^e\) for e >= 1
- Input x and e
- Start with 1 in result
- Multiply result by x
- Subtract 1 from e
- Repeat from 3 only if e > 0
Desktop calculator program for exponent
1: 3 2: store x 3: 5 4: store e 5: 1 6: store result ---------------- 7: recall result 8: * 9: recall x 10: = 11: store result 12: recall e 13: - 14: 1 15: = 16: store e 17: if e>0 goto 7 ----------------------- 18: recall result
# inputs 1: 3 2: store x 3: 5 4: store e 5: 1 6: store result ---------------- # one multiplication 7: recall result 8: * 9: recall x 10: = 11: store result # decrement e 12: recall e 13: - 14: 1 15: = 16: store e # repeat if not done multiplying 17: if e>0 goto 7 ----------------------- 18: recall result
Exponent in C (with goto)
- Use
gotoas in desktop calculator program- To a label instead of a number
repeat: // C code goto repeat;
#include <stdio.h>
#include <assert.h>
int main(int argc, char **argv) {
int x;
int e;
scanf("%d", &x);
scanf("%d", &e);
assert(e >= 1);
int result = 1;
repeat:
result = result * x;
e = e - 1;
if (e > 0) {
goto repeat;
}
printf("%d\n", result);
}
goto can be confusing
- Recall goto fail bug
- "go to statement considered harmful"
- Hard to see what code is repeated
Letters to the editor: go to statement considered harmful Edsger W. Dijkstra
While Loops
while loops
while (condition) {
instructions;
}
- Check the condition
- If the condition is true, run the instructions and repeat from #1
- If the condition is false, don't run the instructions nor repeat
Flow chart
Diagram
- Condition check
- instructions, then go back to condition
- next code
while true
What will be the output of this program?
while (1) {
}
print("done!\n");
Decrement e with while loop
while (e > 0) {
e = e - 1;
}
- Does the program ever end?
- What will be the value of e after the while loop (if it ends)?
#include <stdio.h>
int main(int argc, char **argv) {
int e;
scanf("%d", &e);
int result = 1;
while (e > 0) {
e = e - 1;
}
printf("%d\n", e);
}
Exponent with a while loop
- How do we use while here?
#include <stdio.h>
#include <assert.h>
int main(int argc, char **argv) {
int x;
int e;
scanf("%d", &x);
scanf("%d", &e);
assert(e >= 1);
int result = 1;
repeat:
result = result * x;
e = e - 1;
if (e > 0) {
goto repeat;
}
printf("%d\n", result);
}
#include <stdio.h>
#include <assert.h>
int main(int argc, char **argv) {
int x;
int e;
scanf("%d", &x);
scanf("%d", &e);
assert(e >= 1);
int result = 1;
while (e > 0) {
result = result * x;
e = e - 1;
}
printf("%d\n", result);
}
Differences?
Repeated guessing game
- Guess until right
- Fixed guesses
#include <stdbool.h>
int answer;
int guess;
printf("enter the answer: ");
scan("%d", &answer);
printf("enter the guess: ");
scan("%d", &guess);
while (guess != answer) {
printf("enter the guess: ");
scan("%d", &guess);
}
Factorial
do-while
do {
instructions;
} while (condition);
- Run the instructions
- Check the condition
- If the condition is true, repeat from #1
- If the condition is false, don't repeat repeat
Differences from while
int e;
scan("%d", e);
while (e > 0) {
printf("%d\n", e);
e = e - 1;
}
int e;
scan("%d", e);
do {
printf("%d\n", e);
e = e - 1;
} while (e > 0);
Summary of differences
- while loops: run 0 or more times
- do-while loopsl run 1 or more times
Compare exponent implementations
#include <stdio.h>
#include <assert.h>
int main(int argc, char **argv) {
int x;
int e;
scanf("%d", &x);
scanf("%d", &e);
int result = 1;
do {
result = result * x;
e = e - 1;
} while (e > 0);
printf("%d\n", result);
}
Compare guessing game implementations
Repeated Guessing Game
From homework
Boundary conditions
0, 1, and many
Fencepost problem
0-based or 1-based
Considering all inputs
Tips
- [x, y), inclusive start, exclusive end (easy composition)
0 <= xmeans inclusive,x < 10means exclusive- Know both 0-base (we'll see arrays later) and 1-base (for math-related stuff)
Clean up: exponent
Clean up: factorial
Clean up: finite guessing game
Example: newton's method
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
float a; // the number to find square root of
float x; // the iterative guess
printf("enter a number: ");
/* a = (float) (getchar() - '0'); */
scanf("%f", &a);
printf("a: %f\n", a);
// initially guess half of a
x = a / 2;
printf("initial x: %f\n", x);
while (1) {
x = x - (x * x - a)/(2 * x);
/* x = x - (x * x - a)/(2); */
printf("x: %f\n", x);
sleep(1);
}
}
Console animation
ssh terminal.shop
telnet starwarstel.net
ssh starwarstel.net
Bouncing ball
44 lines of C
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
int width = 40;
int height = 20;
int x = 0;
int y = 0;
int dx = 1;
int dy = 1;
while (1) {
printf("\033[2J");
printf("\033[H");
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
if ((i == x) && (j == y)) {
putchar('o');
} else {
putchar(' ');
}
}
putchar('|');
putchar('\n');
}
for (int i = 0; i < width; i++) {
putchar('^');
}
putchar('\n');
if ((0 <= (x + dx)) && ((x + dx) < width)) {
dx = dx;
} else {
dx = dx * -1;
}
if ((0 <= (y + dy)) && ((y + dy) < height)) {
dy = dy;
} else {
dy = dy * -1;
}
x = x + dx;
y = y + dy;
usleep(50 * 1000);
}
return 0;
}
The char type
A single character
char c; c = 'a'; putchar(a); // prints a character fflush(stdout); // ensure output
Roughly corresponding to keyboard keys. Run man ascii in bash for full set (there are other encodings as well, e.g., EBCDIC, ANSI, and Unicode).
Can also use %c in printf, e.g.,
printf("%c\n", c);
fflush is necessary in the default terminal mode, where output is only sent line-by-line
The newline character \n
\n means "go to the next line"
This is a non-printable character. Instead it controls the cursor of the terminal.
hello, world!\n vs. hello, world!
Terminal controls
Special characters to manipulate the terminal screen
\033[ followed by a code, e.g.,
- clear screen
2J - move cursor back to top-left
H
printf("\033[2J"); // clear screen
printf("\033[H"); // move cursor to top-left of terminal
ANSI Escape Sequences cheatsheet ยท GitHub
Console Virtual Terminal Sequences - Windows Console | Microsoft Learn
ANSI stands for the American National Standards Institute
Timing: sleep
Sleep: wait for a given amount of time
usleep(x) sleep for x microseconds
#include <unistd.h> usleep(50 * 1000); // sleep for 50 milliseconds (50,000 microseconds)
Example: draw with while
while_putchar.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
printf("\x1b[2J"); // clear screen
printf("\x1b[H");
while (1) {
putchar('o');
fflush(stdout);
usleep(50 * 1000);
}
}
Example: movement
move.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
int max = 40;
int x;
x = 0;
while (1) {
printf("\033[2J");
printf("\033[H");
int i = 0;
while (i < max) {
if (x == i) {
putchar('o');
} else {
putchar(' ');
}
i = i + 1;
}
fflush(stdout);
x = (x + 1) % max;
usleep(50 * 1000);
}
}
Start with just printing a characater
Example: 1-dimensional bounce
Add code to change direction
1d_bounce.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
int max = 40;
int x;
int dx;
x = 0;
dx = 1;
while (1) {
printf("\x1b[2J");
printf("\x1b[H");
int i = 0;
while (i < max) {
if (x == i) {
putchar('o');
} else {
putchar(' ');
}
i = i + 1;
}
fflush(stdout);
x = x + dx;
if (0 < x && x < (max - 1)) {
dx = dx;
} else {
dx = dx * -1;
}
usleep(50 * 1000);
}
}
Example: 2-dimensional bounce
Add a y-axis
2d_bounce.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
int width = 40;
int height = 20;
int x = 0;
int y = 0;
int dx = 1;
int dy = 1;
while (1) {
printf("\033[2J");
printf("\033[H");
int j = 0;
while(j < height) {
int i = 0;
while (i < width) {
if ((i == x) && (j == y)) {
putchar('o');
} else {
putchar(' ');
}
i++;
}
putchar('|');
putchar('\n');
j++;
}
for (int i = 0; i < width; i++) {
putchar('^');
}
putchar('\n');
if ((0 <= (x + dx)) && ((x + dx) < width)) {
dx = dx;
} else {
dx = dx * -1;
}
if ((0 <= (y + dy)) && ((y + dy) < height)) {
dy = dy;
} else {
dy = dy * -1;
}
x = x + dx;
y = y + dy;
usleep(50 * 1000);
}
return 0;
}
Build from 1d bounce.
ANSI cursor control
Simplify positioning, horizontal/vertical positioning:
e.g., 3;2H
printf("\033[%d;%dH", 3, 2);
Terminal is a grid of characters (grid in xournal++), starting from 1, 1
bounce with ANSI
bounce_ansi.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
int width = 40;
int height = 20;
int x = 1;
int y = 1;
int dx = 1;
int dy = 1;
while (1) {
printf("\033[2J");
printf("\033[H");
printf("\033[%d;%dH", (int)y, (int)x);
putchar('o');
putchar('\n');
if ((0 < (x + dx)) && ((x + dx) < width)) {
dx = dx;
} else {
dx = dx * -1;
}
if ((0 < (y + dy)) && ((y + dy) < height)) {
dy = dy;
} else {
dy = dy * -1;
}
printf("\033[%d;%dH", height + 1, 0);
printf("y: %d\n", y);
printf("x: %d\n", x);
x = x + dx;
y = y + dy;
usleep(50 * 1000);
}
return 0;
}