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
Kill a program with Ctrl-C
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; }