Breakout, the game the course builds in HiSoft C, running on the Tatung Einstein: coloured brick rows, the bat and the ball on a black court
← Back to Courses
module
14

Asking

Introduction

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.

A Line At A Time

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.

Numbers Straight In

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.

A Character At A Time

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.

One Key, Now

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.

The Code

#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.)

Change One Thing

  • Answer the second question with 40 years. Then with forty. Then with 100000. What does each print, and which of the three is the program's fault?
  • Replace the two 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?
  • Change the second gets(name) to n = rawin(); and remove the atoi line. Press 4. What is printed, and why is it not 4?

Exercises

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.

When It Goes Wrong

SymptomCause
The number read is 0 whatever was typedatoi found no digits at the start of the line - a word, or a space then a letter.
A number comes back wildly wrongIt was over 32,767 (S9).
scanf filled a variable with 0 and said it had read one valueThe typing was not a number. scanf does not report it.
getchar does not return until ENTERIt never does here. For a key at once, rawin.
scanf compiled and the variable is unchanged, or the program misbehavesAn argument without &. scanf needs addresses.
The letter rawin returned is a capitalCAPS LOCK is on.

Summary

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.

Next

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.

Get the Newsletter

New guides, disk images and community finds, roughly once a quarter. No spam, we promise, this isn't Tatung's marketing department.
Your subscription could not be saved. Please try again.
Your subscription has been successful.

Newsletter

Subscribe to our newsletter and stay updated.