
A game has to read the player. So does almost anything else worth writing, and there are two quite different ways of doing it: waiting for a whole line and ENTER, which is how you ask a question, and taking a single key the instant it is pressed, which is how you steer a bat. This section has both, and the messy middle - what you get when the player types abc where you asked for a number.
char name[40];
gets(name);
gets waits for a line, ENTER included, and puts its characters into name, with a 0 after the last one to mark the end (S17 is about that 0). name has to be an array of char big enough for the longest line anyone will type; forty is the width of the screen. Then printf("Hello, %s\n", name) prints it back.
Everything typed is characters, even digits. To get a number out of a line, atoi - ASCII to integer - reads the digits at the start of a string and gives their value:
n = atoi(name);
It is tolerant in the ways you would want. atoi("12") is 12, and so is atoi("12abc"): it stops at the first thing that is not a digit. A leading space is skipped, " 7" is 7, and a minus sign is honoured, "-5" is -5. If there are no digits at all, atoi("abc") is 0 - which is not an error, just 0, so a program that must tell "nothing" from "zero" has to look at the string itself. And atoi("40000") is -25536, because the digits are read faithfully into an int that cannot hold them (S9).
That is the way this course asks for numbers: gets a line, atoi it. It is two steps, and the second can never fail in a way that damages anything.
scanf is printf backwards: a format, and then the addresses of the variables to fill.
n = scanf("%d %d", &a, &b);
&a is "the address of a" - S16 is about that & - and it is needed because scanf has to put a value into a, which a copy of a would not let it do (S13). Given 12 34, this fills a and b and returns 2, the number of values read.
Its weakness is what happens when the typing is not a number. Given abc, scanf("%d", &a) returned 1 - it claimed a value - and put 0 in a. It does not tell you anything went wrong. gets and atoi give the same 0 for the same typing, but with the line still in your hands to look at. The course uses scanf only where the input is certain, and gets with atoi everywhere else.
getchar() returns the next character typed. But on this machine it does not return it when it is typed: nothing arrives until ENTER is pressed, and then the whole line comes through one call at a time, with the ENTER last as a '\n'. So the usual shape is a loop that stops at the newline:
while ((c = getchar()) != '\n')
printf("%d ", c);
Typed HI! and ENTER, that prints 72 73 33 - the codes of the three characters - and stops. The extra brackets around c = getchar() are needed: without them != would be done first, and c would get the 1 or 0 of the comparison.
For a game none of those will do: the player does not press ENTER after every move. rawin() waits for a key and returns it the moment it is pressed, without echoing it to the screen:
c = rawin();
Pressed c, it returns 67 - the code for C, because CAPS LOCK was on when this was run - and the program goes on at once. It still waits, though. A game loop that must keep the ball moving whether or not a key is pressed needs kbd(), which S12 met and S22 finishes: it looks and comes back either way.
#include STDIO.H
main()
{
char name[40];
int n;
printf("What is your name? ");
gets(name);
printf("Hello, %s\n", name);
printf("How old is your Einstein? ");
gets(name);
n = atoi(name);
printf("%d years, or %d months\n", n, n * 12);
}
#include ?STDIO.LIB?
name is reused for the second question: once atoi has taken the number out, the characters are not needed.
Starting from
Typed as ASK.C; compiled and run. At the two questions, type your name and ENTER, then 40 and ENTER.
What you should see
What is your name? GAVIN
Hello, GAVIN
How old is your Einstein? 40
40 years, or 480 months
(The name is in capitals here because CAPS LOCK was on for the run. If you pressed it in S4 to type the program, it is off, and your name comes back as you typed it.)
40 years. Then with forty. Then with 100000. What does each print, and which of the three is the program's fault?gets lines and the atoi with one scanf("%d", &n); after the second question, and answer it with forty. What does n become, and did anything tell you?gets(name) to n = rawin(); and remove the atoi line. Press 4. What is printed, and why is it not 4?14.1 Ask for two numbers on separate lines and print their sum, difference and product.
14.2 Ask for a line and print it backwards, one character per getchar call. (Store the characters in an array first; S15.)
14.3 Print Press any key, wait with rawin, and print the code of the key pressed, in decimal and hexadecimal.
Worked solutions are in Appendix II.
| Symptom | Cause |
|---|---|
| The number read is 0 whatever was typed | atoi found no digits at the start of the line - a word, or a space then a letter. |
| A number comes back wildly wrong | It was over 32,767 (S9). |
scanf filled a variable with 0 and said it had read one value | The typing was not a number. scanf does not report it. |
getchar does not return until ENTER | It never does here. For a key at once, rawin. |
scanf compiled and the variable is unchanged, or the program misbehaves | An argument without &. scanf needs addresses. |
The letter rawin returned is a capital | CAPS LOCK is on. |
gets(array) reads a line; atoi(string) turns its leading digits into an int, 0 if there are none. scanf("%d", &n) reads a number but cannot tell you when it did not. getchar() gives a line's characters one at a time, after ENTER. rawin() gives one key at once, unechoed.
S15, Arrays - rows of values under one name, the two-dimensional grid that Breakout's bricks live in, and what happens when you write past the end.