Fancy input
The typical INPUT statement looks like this:
INPUT "What is your name"; n$
It makes the computer ask "What is your name?" then wait for you to answer the question. So when you run the program, the conversation looks like this:
What is your name? Maria
Notice that the computer automatically adds a question mark at the end of the question, and leaves a blank space after the question mark.
Omitting the question mark
If you want to omit the question mark and the blank space, replace the semicolon by a comma:
INPUT "What is your name", n$
The comma makes the computer omit the question mark and the blank space, so the conversation will look like this:
What is your nameMaria
Here’s a prettier example of how to use the comma:
INPUT "Please type your name...", n$
The conversation will look like this:
Please type your name...Maria
Here’s an even prettier example:
INPUT "To become a movie star, type your name next to the stars***", n$
The conversation will look like this:
To become a movie star, type your name next to the stars***Maria
Omitting the prompt
The typical INPUT statement contains a question, such as "What is your name". The question is called the
prompt. If you wish, you can omit the prompt, like this:INPUT n$
That line doesn’t include a question, but the computer still prints a question mark followed by a blank space, so the conversation looks like this:
? Maria
To make that INPUT line more practical, put a PRINT line above it, like this:
PRINT "Please type your name after the question mark"
INPUT N$
That makes the conversation look like this:
Please type your name after the question mark
? Maria
Adjacent printing
Here’s a simple program:
CLS
INPUT "What is your name"; n$
PRINT "!!!What a wonderful name!!!"
It produces this conversation:
What is your name? MARIA
!!!What a wonderful name!!!
To have more fun, insert a semicolon immediately after the word INPUT, like this:
CLS
INPUT ; "What is your name"; n$
PRINT "!!!What a wonderful name!!!"
The conversation will begin normally:
What is your name? Maria
But when you press the ENTER key after Maria, the extra semicolon makes the computer do the PRINTing next to Maria, like this:
What is your name? Maria!!!What a wonderful name!!!
To surprise your friends, run this program:
CLS
INPUT ; "What is your name"; n$
PRINT n$; n$; n$
The program begins by asking:
What is your name?
Suppose the person says Maria, like this:
What is your name? Maria
When the person presses the ENTER key after Maria, the PRINT line automatically prints Maria three more times afterwards, like this:
What is your name? MariaMariaMariaMaria
This program asks for your first name, then your last name:
CLS
INPUT ; "What is your first name"; first.name$
INPUT " What is your last name"; last.name$
The first INPUT line makes the conversation begin like this:
What is your first name? Maria
When you press the ENTER key after Maria, that INPUT’s extra semicolon makes makes the next INPUT appear on the same line, like this:
What is your first name? Maria What is your last name?
If you answer Yee, the whole conversation looks like this:
What is your first name? Maria What is your last name? Yee
Multiple input
This program asks for your name, age, and weight:
CLS
INPUT "Name, age, weight"; n$, a, w
When you run the program, the computer asks:
Name, age, weight?
The computer waits for you to type your name, age, and weight. When you type them, put commas between them, like this:
Name, age, weight? John,25,148
If your name is "John Smith, Jr.", and you want to input all that instead of just John, you must put quotation marks around your name:
Name, age, weight? "John Smith, Jr.",25,148
Here’s the rule: you must put quotation marks around any INPUT string that contains a comma.
LINE INPUT
If you say —
LINE INPUT "Please type your name..."; n$
the computer will say:
Please type your name...
Then the computer will wait for you to type your name. You do not have to put quotation marks around your name, even if your name contains a comma. LINE INPUT means: the entire line that the person inputs will become the string, even if the line contains a comma.
Notice that the LINE INPUT statement does not make the computer automatically print a question mark. And notice that the variable must be a string (such as n$), not a number.
INPUT$
This program reveals private information about Mary:
CLS
PRINT "Mary secretly wishes to kiss a cow!"
Here’s how to protect that program, so only people who know the "secret password" can run it.…
First, invent a secret password. Let’s make it be "tuna".
Here’s the program:
CLS
INPUT "What's the secret password"; a$
IF a$ = "tuna" THEN
PRINT "Mary secretly wishes to kiss a cow!"
ELSE
PRINT "You are an unauthorized user!"
END IF
The INPUT line asks the person to type the secret password. Whatever the person types is called a$. If the person types "tuna", the computer will say:
Mary secretly wishes to kiss a cow!
But if the person does not type "tuna", the computer says "You are an unauthorized user!" and refuses to reveal Mary’s secret desire.
This program’s better:
CLS
PRINT "Please type the secret password."
a$ = INPUT$(4)
IF a$ = "tuna" THEN
PRINT "Mary secretly wishes to kiss a cow!"
ELSE
PRINT "You are an unauthorized user!"
END IF
Line 2 makes the computer say:
Please type the secret password.
Line 3 waits for the person to input 4 characters. The characters that the person inputs will become a$. For example, suppose the person types t, then u, then n, then a; then a$ will become "tuna" and the computer will reveal Mary’s secret.
While the person inputs the 4 characters, they won’t appear on the screen; they’ll be invisible. That’s to prevent other people in the room from peeking at the screen and noticing the password.
After typing the 4 characters, the person does not have to press the ENTER key. As soon as the person types the 4th character, the computer makes a$ be the 4 characters that the person typed.
Broken computer
This devilish program makes your computer pretend to be broken, so that whenever you press the w key your screen shows an f instead:CLS
DO
a$ = INPUT$(1)
IF a$ = "w" THEN PRINT "f"; ELSE PRINT a$;
LOOP
Line 3 waits for you to type 1 character. The IF line says: if the character you typed was "w", print an "f" on the screen instead; otherwise, print the character you typed. Since that routine is in a DO loop, the computer will repeat the routine forever. For example, if you try to type "the weather is wonderful", you’ll see this on the screen instead:
the feather is fonderful
For an even wilder time, tell the computer to change each "e" to "ooga", by changing the IF line to this:
IF a$ = "e" THEN PRINT "ooga"; ELSE PRINT a$;
Then if you try to type "We are here", you’ll see this on the screen instead:
wooga arooga hoogarooga
Abridged literature
This program gives you a choice of literature:CLS
PRINT "Welcome to the world's great literature, abridged."
PRINT "Which kind of literature would you like?"
PRINT "n: novel"
PRINT "p: poem"
10 PRINT "Please press n or p."
SELECT CASE INPUT$(1)
CASE "n"
PRINT "He: I love you."
PRINT "She: I'm pregnant."
PRINT "He: Let's get married."
PRINT "She: Let's get divorced."
PRINT "He: Let's get back together."
PRINT "She: Too bad you died in the war, but I'll never forget you!"
CASE "p"
PRINT "Noses"
PRINT "Blowses"
CASE ELSE
GOTO 10
END SELECT
The program begins by printing:
Welcome to the world's great literature, abridged.
Which kind of literature would you like?
n: novel
p: poem
Please press n or p.
The SELECT CASE line makes the computer wait for you to press a key. You do not have to press the ENTER key afterwards.
If you press the n key, the computer does the lines indented under CASE "n". Those lines print an abridged novel.
If you press the p key instead, the computer does the lines indented under CASE "p". Those lines print an abridged poem.
If you press neither n nor p, the computer does the line indented under CASE ELSE. That line makes the computer GO back TO line 10, which reminds you to press n or p.
SWAP
The computer understands the word SWAP:
CLS
x = 4
y = 9
SWAP x, y
PRINT x; y
Lines 2 & 3 say x is 4, and y is 9. The SWAP line swaps x with y; so x becomes 9, and y becomes 4. The bottom line prints:
9 4
That example swapped numbers. You can also swap strings:
CLS
a$ = "horse"
b$ = "cart"
SWAP a$, b$
PRINT a$; " "; b$
Lines 2 & 3 say a$ is "horse" and b$ is "cart". The SWAP line swaps a$ with b$; so a$ becomes "cart", and b$ becomes "horse". The bottom line puts the cart before the horse:
cart horse
Shuffling
Here are some cards:
queen of hearts
jack of diamonds
ace of spades
joker
king of clubs
Let’s shuffle them, to put them into a random order.
To begin, put the list of cards into a DATA statement:
CLS
DATA queen of hearts,jack of diamonds,ace of spades,joker,king of clubs
We have 5 cards. Let the queen of hearts be called card$(1), the jack of diamonds be called card$(2), the ace of spades be called card$(3), the joker be called card$(4), and the king of clubs be called card$(5):
n = 5
DIM card$(n)
FOR i = 1 TO n
READ card$(i)
NEXT
Shuffle the cards, by using the following strategy.…
Swap card n with a random card before it (or with itself); then swap card n-1 with a random card before it (or with itself); then swap card n-2 with a random card before it (or with itself); etc. Keep doing that, until you finally reach card 2, which you swap with a random card before it (or with itself). Here’s the code:
RANDOMIZE TIMER
FOR i = n TO 2 STEP -1
SWAP card$(i), card$(1 + INT(RND * i))
NEXT
Finally, print the shuffled deck:
FOR i = 1 TO n
PRINT card$(i)
NEXT
So altogether, here’s the entire program:
CLS
DATA queen of hearts,jack of diamonds,ace of spades,joker,king of clubs
n = 5
DIM card$(n)
FOR i = 1 TO n
READ card$(i)
NEXT
RANDOMIZE TIMER
FOR i = n TO 2 STEP -1
SWAP card$(i), card$(1 + INT(RND * i))
NEXT
FOR i = 1 TO n
PRINT card$(i)
NEXT
The computer will print something like this:
king of clubs
joker
jack of diamonds
queen of hearts
ace of spades
To shuffle a larger deck, change just the DATA and the line saying n=5.
Sorting
Putting words in alphabetical order — or putting numbers in numerical order — is called
sorting.Three-Line Sort
Here are a dozen names: Sue, Ann, Joe, Alice, Ted, Jill, Fred, Al, Sam, Pat, Sally, Moe. Let’s make the computer alphabetize them (sort them).Begin by clearing the screen:
CLS
To make the program run faster, tell the computer that all numbers in the program will be short integers:
DEFINT A-Z
Put the list of names in a DATA statement:
DATA Sue,Ann,Joe,Alice,Ted,Jill,Fred,Al,Sam,Pat,Sally,Moe
We have 12 names:
n = 12
Let Sue by called x$(1), Ann be called x$(2), Joe be called x$(3), etc. Here’s how:
DIM X$(n)
FOR i = 1 TO n
READ x$(i)
NEXT
Alphabetize the names, by using the following strategy.…
Compare the first name against the second; if they’re not in alphabetical order, swap them. Compare the second name against the third; if they’re not in alphabetical order, swap them. Compare the third name against the fourth; if they’re not in alphabetical order, swap them. Continue that process, until you finally compare the last two names. But each time you swap, you must start the whole process over again, to make sure the preceding names are still in alphabetical order. Here’s the code:
10 FOR i = 1 TO n - 1
IF x$(i) > x$(i + 1) THEN SWAP x$(i), x$(i + 1): GOTO 10
NEXT
Finally, print the alphabetized list:
FOR I = 1 TO n
PRINT x$(i)
NEXT
So altogether, the program looks like this:
CLS
DEFINT A-Z
DATA Sue,Ann,Joe,Alice,Ted,Jill,Fred,Al,Sam,Pat,Sally,Moe
n = 12
DIM x$(n)
FOR i = 1 TO n
READ x$(i)
NEXT
10 FOR i = 1 TO n - 1
IF x$(i) > x$(i + 1) THEN SWAP x$(i), x$(i + 1): GOTO 10
NEXT
FOR i = 1 TO n
PRINT x$(i)
NEXT
The computer will print:
Al
Alice
Ann
Fred
Jill
Joe
Moe
Pat
Sally
Sam
Sue
Ted
In that program, the sorting occurs in the FOR loop that begins at line 10. Those three lines are called the
Three-Line Sort.Those three lines form a loop. The part of the loop that the computer encounters the most often is the phrase "IF x$(i) > x$(i + 1)". In fact, if you tell the computer to alphabetize a list of names that’s long (several hundred names), the computer spends the majority of its time repeatedly handling "IF x$(i) > x$(i + 1)".
How long will the computer take to handle a long list of names? The length of time depends mainly on how often the computer encounters the phrase "IF x$(i) > x$(i + 1)".
If the list contains n names, the number of times that the computer encounters the phrase "IF x$(i) > x$(i + 1)" is approximately n3/8. Here are some examples:
n (number of names)
n3 / 8 (approximate number of encounters)10 125
12 216
20 1,000
40 8,000
100 125,000
1,000 125,000,000
For example, the chart says that a list of 12 names requires approximately 216 encounters.
The 216 is just an approximation: the exact number of encounters depends on which list of names you’re trying to alphabetize. If the list is nearly in alphabetical order already, the number of encounters will be less than 216; if the list is in reverse alphabetical order, the number of encounters will be more than 216; but if the list is typical (not yet in any particular order), the number of encounters will be about 216. For the list that we tried (Sue, Ann, Joe, Alice, Ted, Jill, Fred, Al, Sam, Pat, Sally, Moe), the exact number of encounters happens to be 189, which is close to 216.
How long will your computer take to finish sorting? The length of time depends on which computer you have, how many names are in the list, and how long each name is. A typical 486DX-66 computer (handling a list of typical names) requires about .00002 seconds per encounter. Multiplying the number of encounters by .00002 seconds, you get:
Number of names
Encounters (n3 / 8) Time___10 125 .0025 secs
12 216 .00432 secs
20 1,000 .02 secs
40 8,000 .16 secs
100 125,000 2.5 secs
1,000 125,000,000 2500 secs = about 7 hours
Five-Line Sort
To make the program run faster, use the Five-Line Sort instead, which uses this strategy.… Compare the first name against the second (that comparison is called i=1), then compare the second name against the third (that comparison is called i=2), then compare the third name against the fourth (that comparison is called i=3), etc. If you find a pair of names that are out of order, swap them and then recheck the pairs that came before. To "recheck the pairs that came before", start with the most recent pairs and work back toward the first name (FOR j = i TO 1 STEP -1), swapping whenever necessary, until you come to a pair that doesn’t need to be swapped. When you come to a pair that doesn’t need to be swapped, stop the rechecking and proceed to the next i.Here’s the code:
FOR i = 1 TO n - 1
FOR j = i TO 1 STEP -1
IF x$(j) > x$(j + 1) THEN SWAP x$(j), x$(j + 1) ELSE GOTO 10
NEXT
10 NEXT
The IF line says: if x$(j) and x$(j + 1) are out of order, SWAP them; but if they’re not out of order, get out of the j loop and GOTO the NEXT i instead.
Even though that Five-Line Sort is longer to type than the Three-Line Sort, the computer handles the Five-Line Sort faster, because its "GOTO 10" lets the computer hop ahead to the NEXT i instead of forcing the computer to go back to the "FOR i = 1".
For the Five-Line Sort, the number of times the computer encounters the phrase "IF x$(j) > x$(j + 1)" is just n2/4:
Number of names
Encounters (n2 / 4) Time__10 25 .0005 secs
12 36 .00072 secs
20 100 .002 secs
40 400 .008 secs
100 2,500 .05 secs
1,000 250,000 5 secs
Eight-Line Sort
The Five-Line Sort compares just adjacent pairs: x$(j) and x$(j+1). The Eight-Line Sort compares pairs that are farther apart: x$(j) and x$(j+d), where d is a big distance. So the Eight-Line Sort resembles the Five-Line Sort but says +d instead of +1, and says -d instead of -1:FOR i = 1 TO n - d
FOR j = i TO 1 STEP -d
IF x$(j) > x$(j + d) THEN SWAP x$(j), x$(j + d) ELSE GOTO 10
NEXT
10 NEXT
But how big is d?
Begin by making d be a big number, about 1/3 as big as n, and perform those five lines. Then divide by 3 again, so d becomes about 1/9 as big as n, and perform those five lines again. Then divide by 3 again, so d becomes about 1/27 as big as n, and perform those five lines again. Keep dividing by 3, until d finally becomes 1, which makes those five lines act exactly the same as the Five-Line Sort. But during that last pass through the data, when d is 1, the computer performs the five lines very quickly, since the earlier passes already put the names into roughly alphabetical order by comparing pairs that were far apart.
Moreover, those early passes consumed very little time, since during those passes the computer did the FOR j loop very few times. (It did that loop few times because it said to "STEP -d", where d was a big number.)
Here’s the complete Eight-Line Sort:
d = n
2 d = d \ 3 + 1
FOR i = 1 TO n - d
FOR j = i TO 1 STEP -d
IF x$(j) > x$(j + d) THEN SWAP x$(j), x$(j + d) ELSE GOTO 10
NEXT
10 NEXT
IF d > 1 THEN GOTO 2
In line 2, the symbol "\" says to do integer division, so the computer will divide by 3 but ignore all digits after the decimal point. Altogether, line 2 says this: to get the new d, divide the old d by 3 (ignoring all digits after the decimal point) and then add 1. That "+ 1" makes the new d be slightly more than the old d divided by 3.
For the Eight-Line Sort, the number of times the computer encounters the phrase "IF x$(j) > x$(j + d)" is just 1.5*(n-1)^(4/3):
Number of names
Encounters Time__10 28 .00056 secs
12 37 .00074 secs
20 76 .00152 secs
40 198 .00396 secs
100 687 .01374 secs
1,000 14,980 .2996 secs
Notice that the Eight-Line Sort handles 1,000 names in .2996 seconds. That’s much faster than the Five-Line Sort, which takes 5 seconds. But to handle just 10 names, the Eight-Line Sort does not run faster than the Five-Line Sort. So use the Eight-Line Sort just for handling long lists of names.
We’ve sure come a long way! To alphabetize 1,000 names, the Three-Line Sort took about 7 hours; the Five-Line Sort took 5 seconds; the Eight-Line Sort took about .3 seconds.
If you try running those sorting methods on your computer, you’ll find the timings are different, since the exact timings depend on which computer you have, the length of each name, and how badly the names are out of order.
Famous sorts
Though I "invented" all those sorting methods, most of them just improve a little on methods developed by others. For example, the Five-Line Sort improves slightly on the Shuttle Sort, which was invented by Shaw & Trimble in 1983. The Eight-Line Sort improves slightly on the Shell Sort, which was invented by Donald Shell in 1959 and further developed by Hibbard & Boothroyd in 1963, Peterson & Russell in 1971, and Knuth in 1973.Phone directory
Suppose you want to alphabetize this phone directory:Name
Phone numberMary Smith 277-8139
John Doe 513-9134
Russ Walter 666-2666
Information 555-1212
Just use one of the alphabetizing programs I showed you! Type the DATA like this:
DATA Smith Mary 277-8139,Doe John 513-9134
DATA Walter Russ 666-2666,Information 555-1212
The computer will print:
Doe John 513-9134
Information 555-1212
Smith Mary 277-8139
Walter Russ 666-2666
Sorting numbers
Suppose you want to put a list of numbers into increasing order. For example, if the numbers are 51, 4.257, -814, 62, and .2, let’s make the computer print:-814
.2
4.257
51
62
To do that, just use one of the alphabetizing programs I showed you — but in the DATA statement, put the numbers instead of strings, and say "x!" instead of "x$".
To put a list of numbers into decreasing order, begin by writing a program that puts them into increasing order, and then change each "> x" to "< x".
Sequential data files
Here’s a simple program:
CLS
PRINT "eat"
PRINT 2 + 2
PRINT "eggs"
It makes the computer print this message onto your screen:
eat
4
eggs
Instead of printing that message onto your screen, let’s make the computer print the message onto your disk. Here’s how.…
OPEN FOR OUTPUT
This program prints the message onto your disk, instead of onto your screen:
CLS
OPEN "joan" FOR OUTPUT AS 1
PRINT #1, "eat"
PRINT #1, 2 + 2
PRINT #1, "eggs"
CLOSE
Those PRINT lines make the computer print the message onto your disk instead of onto your screen. Each line says PRINT #1, which means: print onto the disk.
The OPEN line is an introductory line that tells the computer where on the disk to print the message. The OPEN line says: find a blank place on the disk, call it JOAN, and make JOAN be file #1. So PRINT #1 will mean: print onto file #1, which is JOAN.
Any program that says OPEN should also say CLOSE
, so the bottom line says CLOSE. The CLOSE line makes the computer put some "finishing touches" on JOAN, so that JOAN becomes a perfect, finished file.When you run that program, the computer will automatically put onto the disk a file called JOAN that contains this message:
eat
4
eggs
After running that program, try this experiment.… Exit from QBASIC (by choosing Exit from the File menu), so the computer says:
C:\>
After that C prompt, type "dir", so the screen looks like this:
C:\>dir
When you press the ENTER key at the end of that line, the computer will print the names of all the disk’s files — and one of the names it prints will be JOAN.
After the C prompt, try saying "type joan", like this:
C:\>type joan
That makes the computer show you what’s in JOAN; the computer will say:
eat
4
eggs
OPEN FOR INPUT
To see the message that’s in JOAN, run this program, which inputs from JOAN and prints onto your screen:
CLS
OPEN "joan" FOR INPUT AS 1
INPUT #1, a$
PRINT a$
INPUT #1, b
PRINT b
INPUT #1, c$
PRINT c$
CLOSE
The OPEN line prepares the computer to input from JOAN.
The next line inputs a$ from JOAN, so a$ is "eat". The next line prints "eat" onto your screen.
The next pair of lines input b from JOAN (so b is 4) and print 4 onto your screen. The next pair of lines input c$ from JOAN (so c$ is "eggs") and print "eggs" onto your screen. So altogether, on your screen you’ll see:
eat
4
eggs
The CLOSE line tells the computer that you’re done using JOAN for a while (until you say OPEN again).
OPEN FOR APPEND
After you’ve put JOAN onto the disk, so that JOAN consists of "eat" and 4 and "eggs", try running this program:
CLS
OPEN "joan" FOR APPEND AS 1
PRINT #1, "good morning!"
CLOSE
In the OPEN line, the word APPEND tells the computer to keep adding onto JOAN. So when the computer comes to the PRINT line, it adds "good morning" onto JOAN, and JOAN becomes this:
eat
4
eggs
good morning!
Erasing
For your next experiment, try running this program:
CLS
OPEN "joan" FOR OUTPUT AS 1
PRINT #1, "pickles are pleasant"
CLOSE
Since the OPEN line does not say APPEND, the computer will not keep adding onto JOAN. Instead, the computer erases everything that’s been in JOAN. So when the computer finishes processing line 10, JOAN’s become blank.
The PRINT line puts "pickles are pleasant" into JOAN. So at the end of the program, JOAN includes "pickles are pleasant"; but JOAN does not include "eat" and 4 and "eggs" and "good morning", which have all been erased.
OUTPUT or INPUT or APPEND?
In the OPEN line, you can say OUTPUT or INPUT or APPEND. Here’s how they differ:
If the OPEN line says FOR INPUT, the program can say INPUT #1 but cannot say PRINT #1.
If the OPEN line says FOR OUTPUT, the program can say PRINT #1 but cannot say INPUT #1.
If the OPEN line says FOR APPEND, the program can say PRINT #1 but usually not INPUT #1.
Here’s what happens if you say OPEN "joan" and the file JOAN exists already:
FOR INPUT makes the computer use JOAN without changing JOAN.
FOR APPEND makes the computer use JOAN and lengthen it (by appending extra lines to its end).
FOR OUTPUT makes the computer erase JOAN and then create a totally new JOAN.
Here’s what happens if you say OPEN "joan" when JOAN doesn’t exist yet:
FOR OUTPUT or FOR APPEND makes the computer create JOAN.
FOR INPUT makes the computer gripe and say "File not found".
The following program plays a trick: if JOAN doesn’t exist yet, the program creates JOAN; if JOAN exists already, the program leaves JOAN alone.
CLS
OPEN "joan" FOR APPEND AS 1
CLOSE
Loops
This program lets you put the names of all your friends onto the disk:
CLS
OPEN "friends" FOR OUTPUT AS 1
DO
PRINT "Please type a friend's name (or the word 'end')"
INPUT friend$: IF friend$ = "end" THEN EXIT DO
PRINT #1, friend$
LOOP
CLOSE
The OPEN line makes the computer find a blank space on the disk and call it FRIENDS. The first PRINT line makes the computer print:
Please type a friend's name (or the word 'end')
The INPUT line prints a question mark and waits for you to type something; whatever you type will be called friend$. For example, if you type Mary Williams, then friends$ will be Mary Williams, and the next line prints the name Mary Williams onto the disk.
The lines are in a DO loop, so that you can type as many names as you wish. (Remember to press the ENTER key after each name.)
When you’ve finished typing the names of all your friends, type the word "end". Then the last part of the INPUT line will make the computer EXIT from the DO loop and CLOSE the file.
This program makes the computer look at the FRIENDS file and copy all its names to your screen:
CLS
OPEN "friends" FOR INPUT AS 1
DO UNTIL EOF(1)
INPUT #1, friend$
PRINT friend$
LOOP
CLOSE
PRINT "Those are all the friends."
The OPEN line prepares the computer to input from the FRIENDS file. The lines DO and LOOP make the computer do the indented lines repeatedly. The first indented line makes the computer input a string from the file and call the string friend$; so friend$ becomes the name of one of your friends. The next indented line prints that friend’s name onto your screen. Since those indented lines are in a loop, the names of all your friends are printed on the screen.
Eventually, the computer will reach the end of the file, and there won’t be any more names to input from the file. In the DO line, the "UNTIL EOF(1)" means: if the computer reaches the End Of the File and can’t input any more names from it, the computer should stop looping and proceed to the line underneath LOOP. That line makes the computer CLOSE the file. Then the computer will print on your screen, "Those are all the friends."
As that program illustrates, to read from a file you create a DO loop. Above the loop, say OPEN FOR INPUT; below the loop, say CLOSE; in the loop, say INPUT #1; next to the DO, say UNTIL EOF(1).
LOF
In the middle of your program, if you say PRINT LOF(1), the computer will tell you the Length Of the File: it will tell you how many bytes are in the file.
Multiple files
If you want the computer to handle two files simultaneously, use two OPEN statements. At the end of the first OPEN statement, say "AS 1"; at the end of the second OPEN statement, say "AS 2".
For the second file, say PRINT #2 instead of PRINT #1, say INPUT #2 instead of INPUT #1, say EOF(2) instead of EOF(1), and say LOF(2) instead of LOF(1).
How to CLOSE
The CLOSE statement closes all files. To be more specific, you can say CLOSE 1 (which closes just the first file) or CLOSE 2 (which closes just the second).
Whenever you’re done using a file, CLOSE it immediately. When you say CLOSE, the computer puts finishing touches on the file that protect the file against damage.
Suppose that halfway through your program, you finish using file 2 but want to continue using file 1. Say CLOSE 2 there, and delay saying CLOSE 1 until later.
Random access
On a disk, you can store two popular kinds of data files. The simple kind is called a
sequential-access data file; the complicated kind is called a random-access data file. You’ve already learned how to create and retrieve a sequential-access file. Now let’s look at random-access.Though more complicated than sequential-access data files,
random-access data files have an advantage: they let you skip around. In a sequential-access data file, you must look at the first item of data, then the second, then the third, etc. In a random-access data file, you can look at the seventh item of data, then skip directly to the tenth, then hop back to the third, then skip directly to the sixth, etc.Each item is called a
record. The number of characters (bytes) in the record is called the record’s length. For example, if a record contains 20 characters, the record’s length is 20. In a random-access file, all records must have the same length as each other.PUT
Here’s how to write a program that creates a random-access file.
Begin the program by saying:
CLS
Let’s make each record be a string containing 20 characters:
DIM record AS STRING * 20
Let’s make the file’s name be JIM:
OPEN "jim" FOR RANDOM AS 1 LEN = LEN(record)
Let’s make JIM’s 7th record be "Love makes me giggle" (which contains 20 characters):
record = "Love makes me giggle"
PUT 1, 7, record
Let’s make JIM’s 9th record be "Please hold my hand":
record = "Please hold my hand"
PUT 1, 9, record
Since JIM’s record length is supposed to be 20 characters but "Please hold my hand" contains just 19 characters, the computer will automatically add a blank to the end of "Please hold my hand".
Let’s make JIM’s 4th record be "I love Lucy":
record = "I love Lucy"
PUT 1, 4, record
The computer will automatically add blanks to the end of "I love Lucy".
To finish the program, say:
CLOSE
So altogether, the program looks like this:
CLS
DIM record AS STRING * 20
OPEN "jim" FOR RANDOM AS 1 LEN = LEN(record)
record = "Love makes me giggle"
PUT 1, 7, record
record = "Please hold my hand"
PUT 1, 9, record
record = "I love Lucy"
PUT 1, 4, record
CLOSE
When you run that program, the computer will automatically put onto the disk a file called JIM in which each record is a 20-character string.
After running that program, try this experiment.… Exit from QBASIC (by choosing Exit from the File menu), so the computer says:
C:\>
After that C prompt, type "dir". The computer will print the names of all the disk’s files — and one of the names it prints will be JIM.
After the C prompt, try saying "copy jim con /b". The computer will show you what’s in JIM. You’ll see that JIM includes "I love Lucy" (in the 4th record), "Love makes me giggle" (in the 7th record), and "Please hold my hand" (in the 9th record). Since the program didn’t say what to put into the other records, those other records still contain
garbage (whatever data was sitting on that part of the hard disk before the program ran).GET
This program makes the computer tell you JIM’s 7th item:
CLS
DIM record AS STRING * 20
OPEN "jim" FOR RANDOM AS 1 LEN = LEN(record)
GET 1, 7, record
PRINT record
CLOSE
Multi-field records
Let’s write a program that creates a fancier random-access file.
As usual, begin by saying:
CLS
Let’s make each record be a combination of two parts:
The record’s first part, called "part a", will be a string of 20 characters.
The record’s second part, called "part b", will be a string of 5 characters.
Here’s how:
TYPE combination
a AS STRING * 20
b AS STRING * 5
END TYPE
DIM record AS combination
Let’s make the file be called JACK:
OPEN "jack" FOR RANDOM AS 1 LEN = LEN(record)
Let’s make the 6th record’s first part be "I want turkey on rye" and the second part be "yummy":
record.a = "I want turkey on rye"
record.b = "yummy"
PUT 1, 6, record
To finish the program, say:
CLOSE
So altogether, here’s the program:
CLS
TYPE combination
a AS STRING * 20
b AS STRING * 5
END TYPE
DIM record AS combination
OPEN "jack" FOR RANDOM AS 1 LEN = LEN(record)
record.a = "I want turkey on rye"
record.b = "yummy"
PUT 1, 6, record
CLOSE
Go ahead: run that program!
Then run the following program, which makes the computer tell you JACK’s 6th record:
CLS
TYPE combination
a AS STRING * 20
b AS STRING * 5
END TYPE
DIM record AS combination
OPEN "jack" FOR RANDOM AS 1 LEN = LEN(record)
GET 1, 6, record
PRINT record.a
PRINT record.b
CLOSE
Lengths
If you say
PRINT LOF(1), the computer will tell you the Length Of the File (how many bytes are in the file). If you say PRINT LEN(record), the computer will tell you the LENgth of a record (how many bytes are in a record).Since LOF(1) is the length of the file, and LEN(record) is the length of a record, this line makes the computer tell you how many records are in the file:
PRINT LOF(1) \ LEN(record)
End of the file
The EOF function doesn’t work well for random-access files. To deal with the end of the file, use the following trick instead.
Since the number of records in the file is LOF(1) \ LEN(record),
these lines print all the records:FOR i = 1 TO LOF(1) \ LEN(record)
GET 1, i, record
PRINT record.a
PRINT record.b
NEXT
Numeric data
To make each record consist of a 20-character string followed by a 5-character string, you learned to say this:
TYPE combination
a AS STRING * 20
b AS STRING * 5
END TYPE
DIM record AS combination
Here’s how to make each record consist of a 20-character string followed by a short INTEGER followed by a LONG integer followed by a SINGLE-precision real number followed by a DOUBLE-precision real number:
TYPE combination
a AS STRING * 20
b AS INTEGER
c AS LONG
d AS SINGLE
e AS DOUBLE
END TYPE
DIM record AS combination
A short INTEGER consumes 2 bytes, a LONG integer consumes 4 bytes, a SINGLE-precision real number consumes 4 bytes, and a DOUBLE-precision real number consumes 8 bytes; so in that example, the record’s length is 20 + 2 + 4 + 4 + 8, which is 38 bytes.
Descriptive variables
Instead of talking about "part a" and "part b" of a record, you can pick names that are more descriptive. For example, if a record consists of a person’s nickname and age, you can say:
TYPE combination
nickname AS STRING * 10
age AS integer
END TYPE
DIM record AS combination
To make the 6th record contain my nickname (Russy-poo) and age (48), say:
record.nickname = "Russy-poo"
record.age = 48
PUT 1, 6, record
LOC
If you say
PRINT LOC(1), the computer tells you which record it just dealt with. It tells you the record’s LOCation.For example, if you say "PUT 1, 7, record" or "GET 1, 7, record" and then say PRINT LOC(1), the computer prints the number 7.
Instead of saying "PUT 1, 7, record" or "PUT 1, 8, record", you can leave the record’s number blank and say just:
PUT 1, , record
That makes the computer PUT the next record. For example, it will PUT the 9th record if the previous PUT or GET mentioned the 8th. Saying "PUT 1, , record" has the same effect as saying "PUT 1, LOC(1) + 1, record".
If you say —
GET 1, , record
the computer will GET the next record. For example, it will GET the 9th record if the previous PUT or GET mentioned the 8th.
Multiple files
If you want the computer to handle two random-access files simultaneously, use two OPEN statements. In the first OPEN statement, say "AS 1 LEN = LEN(record)"; in the second OPEN statement, say "AS 2 LEN = LEN(record2)".
For the second file, say 2 instead of 1 (in the OPEN, PUT, and GET statements and in the LOF and LOC functions); say combination2 instead of combination; and say record2 instead of record.
Create a database
I’m going to show you how to write a program that creates a database, in which you can store information about your friends & enemies, your business & bills, birthdays & appointments, desires & dreads, and whatever else bothers you.
Here’s how the program works.…
When you run the program, the computer begins by asking, "What topic interests you?" If you type a topic the computer knows about, the computer will tell you what data it knows about that topic; then the computer will let you change that data. If you type a topic that the computer doesn’t know anything about, the computer will admit ignorance then let you teach the computer about that topic.
After dealing with the topic you requested, the computer will let you request additional topics.
If you type a question mark, the computer will print a list of all the topics in its database so far. If you type an x, the computer will exit from the program.
Simple chronological database
The simplest way to write the program is to write a main procedure and seven SUB procedures:
Allow 3000 topics & data about them. Share with SUBs.
DIM SHARED topic$(3000), data$(3000)Share these variables with the SUBs.
COMMON SHARED topic.desired$, data.inputted$, n, iMake n (the number of topics) start at 0.
n = 0Do the following loop repeatedly:
DOClear the screen.
CLSAsk the human, "What topic interests you?"
PRINT "What topic interests you? ";Remind the human to type "?" if unsure, "x" to exit.
PRINT "(If unsure, type a question mark. To exit, type an x.)"Make the human’s response be called topic.desired$.
10 LINE INPUT topic.desired$If human confused, list all topics & ask human again.
IF topic.desired$ = "?" THEN list.all.topics: GOTO 10If the human’s response is "x", exit from the program.
IF topic.desired$ = "x" THEN ENDOtherwise, capitalize the response & delete extra blanks.
topic.desired$ = UCASE$(LTRIM$(RTRIM$(topic.desired$)))Search for the topic that the human requested.
search.for.topicRepeat that loop until the human types "x".
LOOPHere’s how to list all topics:
SUB list.all.topicsClear the screen.
CLSIf there are no topics yet, do this:
IF n = 0 THENSay "I don’t know any topics yet."
PRINT "I don't know any topics yet. My mind is still blank. ";Say "Please teach me a new topic."
PRINT "Please teach me a new topic."If some topics exist, do this:
ELSESay "I know about these topics".
PRINT "I know about these topics:"Leave a blank line underneath that heading.
PRINTFor every individual topic in the database,
FOR i = 1 TO nprint that topic, then hop to the next zone.
PRINT topic$(i),When you finish printing all the topics,
NEXTreturn to the screen’s left margin
PRINTand leave a blank line
PRINTthen say "Pick one of those or teach me a new one."
PRINT "Pick one of those topics, or teach me a new one."At the end of all that,
END IFask the human again, "What topic interests you?"
PRINT "What topic interests you? (To exit, type an x.)"END SUB
Here’s how to search for the topic the human requested:
SUB search.for.topicStart to look at every individual topic in the database.
FOR i = 1 TO nIf a topic’s the one desired, just do "found.the.topic".
IF topic$(i) = topic.desired$ THEN found.the.topic: EXIT SUBIf the desired topic is not in the database,
NEXTthe topic is missing, so do "missing.topic".
missing.topicEND SUB
Here’s how to act when situation is "found.the.topic":
SUB found.the.topicClear the screen.
CLSSay "Here’s what I know about" the topic.
PRINT "Here's what I know about "; topic.desired$; ":"Print the data that’s in the database about that topic.
PRINT data$(i)Leave a blank line.
PRINTAsk "Do you want to change that information?"
INPUT "Do you want to change that information"; response$If the human says "yes" or "y", change the info.
IF response$ = "yes" OR response$ = "y" THEN change.the.infoEND SUB
Here’s how to change the info:
SUB change.the.infoSay that the computer’s erased old info about the topic.
PRINT "Okay. I've erased that information about "; topic.desired$; "."Leave a blank line.
PRINTTell the human to input new info about the topic.
PRINT "Type what you want me to know about "; topic.desired$; "."Say that typing an x will delete the topic.
PRINT "(If you want me to forget about "; topic.desired$; ", type an x.)"Wait for the human’s response.
LINE INPUT data.inputted$If response is x, delete the topic; if not x, use new data.
IF data.inputted$ = "x" THEN delete.the.topic ELSE data$(i) = data.inputted$END SUB
Here’s how to delete the topic:
SUB delete.the.topicReplace that topic by the last topic (topic #n).
topic$(i) = topic$(n)Replace that topic’s data by the last topic’s data.
data$(i) = data$(n)Decrease the number of topics, by subtracting 1.
n = n - 1END SUB
Here’s how to act when situation is "missing.topic":
SUB missing.topicClear the screen.
CLSSay "I don’t know anything about" that topic.
PRINT "I don't know anything about "; topic.desired$; "."Say "Please tell me about" that topic.
PRINT "Please tell me about "; topic.desired$; "."Say "If you don’t want to tell me, type an x."
PRINT "(If you don't want to tell me, type an x.)"Wait for the human’s response.
LINE INPUT data.inputted$If the human didn’t type an x, insert the topic.
IF data.inputted$ <> "x" THEN insert.the.topicEND SUB
Here’s how to insert the topic:
SUB insert.the.topicIncrease the number of topics, by adding 1.
n = n + 1Append the new topic. Make it topic #n.
topic$(n) = topic.desired$Also append the new topic’s data. Make it data #n.
data$(n) = data.inputted$END SUB
The program stores the topics in
chronological order: if you begin by feeding it information about SUE and then information about CAROL, it will let topic$(1) be "SUE" and let topic$(2) be "CAROL".Copy to disk
That program stores the data just in the RAM — not on a disk. When you turn off the power, the RAM forgets all the data!
Let’s write a fancier version that copies the data onto the hard disk before the program ends.
To write the fancier version, just change the main procedure; the seven SUB procedures remain the same! Here’s how to write the main procedure:
Allow 3000 topics & data about them. Share with SUBs.
DIM SHARED topic$(3000), data$(3000)Share these variables with the SUBs.
COMMON SHARED topic.desired$, data.inputted$, n, iIf the database file doesn’t exist yet, create it
OPEN "database" FOR APPEND AS 1and polish it up.
CLOSEPrepare to copy from hard disk’s database file to RAM.
OPEN "database" FOR INPUT AS 1Make n (the number of topics) start at 0.
n = 0Repeat the following, until reaching end of database file:
DO UNTIL EOF(1)Increase the number of topics
n = n + 1becausee inputting another topic from the database file
LINE INPUT #1, topic$(n)and inputting the topic’s data.
LINE INPUT #1, data$(n)Do that repeatedly until the database is done,
LOOPthen close the database file.
CLOSEDo the following loop repeatedly:
DOClear the screen.
CLSAsk the human, "What topic interests you?"
PRINT "What topic interests you? ";Remind the human to type "?" if unsure, "x" to exit.
PRINT "(If unsure, type a question mark. To exit, type an x.)"Make the human’s response be called topic.desired$.
10 LINE INPUT topic.desired$If human confused, list all topics & ask human again.
IF topic.desired$ = "?" THEN list.all.topics: GOTO 10If the human’s response is "x", exit from the loop.
IF topic.desired$ = "x" THEN EXIT DOOtherwise, capitalize the response & delete extra blanks.
topic.desired$ = UCASE$(LTRIM$(RTRIM$(topic.desired$)))Search for the topic that the human requested.
search.for.topicRepeat that loop until the human types "x".
LOOPPrepare to copy from RAM to hard disk’s database file.
OPEN "database" FOR OUTPUT AS 1For all the topics,
FOR i = 1 TO ncopy topic from the RAM to the hard disk’s database file
PRINT #1, topic$(i)and also copy the topic’s data.
PRINT #1, data$(i)Do that repeatedly, until all the topics are done,
NEXTthen close the database file.
CLOSEAlphabetical database
Instead of chronological order, you might prefer
alphabetical order.For example, suppose you feed the computer information about SUE then CAROL then ZELDA then ALICE then JANE. Here’s what the computer’s memory would look like, in each kind of order:
Chronological order
Alphabetical orderSUE ALICE
CAROL CAROL
ZELDA JANE
ALICE SUE
JANE ZELDA
Which is better: chronological order or alphabetical order?
Chronological order lets you quickly add a new name (just add it at the end of the list), but finding a name in the list is slow (since the list looks disorganized). Alphabetical order lets you find a name faster (since the list is alphabetized), but adding a new name to the alphabetized list is slow (since the only way to insert the new name is to make room for it by shoving other names out of the way).
So which is better?
Chronological order
is the simplest to program and the fastest for inserting.Alphabetical order
is the fastest for finding information.If you want to store the names in alphabetical order instead of chronological order, use these new versions of three SUB procedures:
Here’s how to search for the topic the human requested:
SUB search.for.topicWhat’s the topic’s position in database? 0 is "too low",
too.low = 0but n + 1 is "too high".
too.high = n + 1Try guesses in between, as follows:
DOFind average (rounded up) of "too low" & "too high".
i = (too.low + too.high + 1) \ 2If average is too high, just do "missing.topic".
IF i = too.high THEN missing.topic: EXIT SUBIf the topic is found, just do "found.the.topic".
IF topic$(i) = topic.desired$ THEN found.the.topic: EXIT SUBOtherwise, adjust "too high" or "too low",
IF topic$(i) > topic.desired$ THEN too.high = i ELSE too.low = ithen try another guess.
LOOPEND SUB
Here’s how to delete the topic:
SUB delete.the.topicDecrease the number of topics.
n = n - 1Close the gap from the deleted topic,
FOR j = i TO nby moving topics
topic$(j) = topic$(j + 1)and their data.
data$(j) = data$(j + 1)NEXT
END SUB
Here’s how to insert the topic:
SUB insert.the.topicIncrease the number of topics.
n = n + 1To make room for the new topic,
FOR j = n TO i + 1 STEP -1move other topics out of the way
topic$(j) = topic$(j - 1)and move their data.
data$(j) = data$(j - 1)When the moving is done,
NEXTinsert the new topic
topic$(i) = topic.desired$and its data.
data$(i) = data.inputted$END SUB
That new version of search.for.topic runs faster than the chronological version, because searching through an alphabetical list is faster than searching through a chronological list. (To search through the alphabetical list super-quickly, the new version of search.for.topic uses a trick called
binary search.)Unfortunately, the new versions of delete.the.topic and insert.the.topic run slower than the chronological versions. To get the high speed of the new search method, you must accept the slowness of the new delete & insert methods.
You’ve seen that chronological order is fast for inserting and deleting but slow for searching, whereas alphabetical order is exactly the opposite: it’s fast for searching but slow for inserting or deleting.
Tree-structured database
Instead of using chronological order or alphabetical order, advanced programmers use a
tree. Like chronological order, a tree lets you insert and delete quickly. Like alphabetical order, a tree lets you search quickly also.Poets say, "only God can make a tree." Does that mean advanced programmers are God?
To learn how to make a tree, begin by sketching a picture of a tree on paper. Since N is the alphabet’s middle letter, begin by writing the letter N, and put two arrows underneath it:
N
The left arrow is called the
before-arrow; it will point to the names that come alphabetically before N. The right arrow is called the after-arrow; it will point to the names that come alphabetically after N.For example, suppose your first topic is SUE. Since SUE comes alphabetically after N, put SUE at the tip of N’s after-arrow:
N
SUE
Suppose your next topic is CAROL. Since CAROL comes alphabetically before N, put CAROL at the tip of N’s before-arrow:
N
CAROL SUE
Suppose your next topic is ZELDA. Since ZELDA comes after N, we’d like to put ZELDA at the tip of N’s after-arrow; but SUE’s already stolen that position. So compare ZELDA against SUE. Since ZELDA comes after SUE, put ZELDA at the tip of SUE’s after-arrow:
N
CAROL SUE
ZELDA
Suppose your next topic is ALICE. Since ALICE comes before N, look at the tip of N’s before-arrow. Since CAROL’s stolen that position, compare ALICE against CAROL; since ALICE comes before CAROL, put ALICE at the tip of CAROL’s before-arrow:
N
CAROL SUE
ALICE ZELDA
Suppose your next topic is JANE. Since JANE comes before N, look at the tip of N’s before-arrow. Since CAROL’s stolen that position, compare JANE against CAROL; since JANE comes after CAROL, put JANE at the tip of CAROL’s after-arrow:
N
CAROL SUE
ALICE JANE ZELDA
If the next few topics are FRED, then LOU, then RON, then BOB, the tree looks like this:
N
CAROL SUE
ALICE JANE RON ZELDA
BOB FRED LOU
Look at the arrows that point down from N. N’s before-arrow points to the group of names that come alphabetically before N (such as CAROL, ALICE, JANE, BOB, FRED, and LOU); N’s after-arrow points to the group of names that come alphabetically after N (such as SUE, RON, and ZELDA). Similarly, CAROL’s before-arrow points to the group of names that come alphabetically before CAROL (such as ALICE and BOB); CAROL’s after-arrow points to the group of names that come alphabetically after CAROL (such as JANE, FRED, and LOU).
Programmers treat the tree as if it were a "family tree". CAROL is called the
parent of ALICE and JANE, who are therefore called CAROL’s children. CAROL is called the ancestor of ALICE, JANE, BOB, FRED, and LOU, who are therefore called CAROL’s descendants. The arrows are called pointers.To make the tree more useful, begin with "N !" instead of "N" (so you can choose "N" as a topic later), and number the topics in the order they appeared: since SUE was the first topic, put "1" in front of SUE; since CAROL was the second topic, put "2" in front of CAROL; since ZELDA was the third topic, put "3" in front of ZELDA, like this:
N !
2CAROL 1SUE
4ALICE 5JANE 8RON 3ZELDA
9BOB 6FRED7LOU
To describe the tree to the computer, store this table in the computer’s memory:
Topic
Where the before-arrow points Where the after-arrow points0 N ! 2 1
1 SUE 8 3
2 CAROL 4 5
3 ZELDA 0 0
4 ALICE 0 9
5 JANE 6 7
6 FRED 0 0
7 LOU 0 0
8 RON 0 0
9 BOB 0 0
That table
represents the tree and is called the tree’s representation.The table’s left column is in chronological order, but the other columns give information about alphabetizing. So a tree combines chronological order with alphabetical order: it combines the advantages of both. Adding a new topic to the tree is quick and easy (as in chronological order): just add the name to the bottom of the list, and adjust a few arrows. Using the tree to search for a topic is quick and easy (as in alphabetical order): just follow the arrows.
Editions 11-20 of this book contained a program that created a tree in a random-access data file. Phone me at 617-666-2666 to find out which editions are still available and their prices. But the best way to create a big, sophisticated database is to buy a database program such as
Q&A (which I explained in the database chapter) or use a database programming language such as DBASE (which I’ll explain in the next chapter).SHELL
In the middle of your program, you can make the computer perform a DOS command! Just
say SHELL, and put the DOS command in quotation marks.For example, this program tells you which version of DOS you’re using:
CLS
SHELL "ver"
This program displays a directory of all your files:
CLS
SHELL "dir /w"
This program changes the name JOE.BAS to FRED.BAS:
CLS
SHELL "rename joe.bas fred.bas"
This program deletes JOE.BAS from your hard disk:
CLS
SHELL "del joe.bas"
This program makes the computer run Windows:
CLS
SHELL "win"
Short cuts
Here are some short cuts:
To see what files are on your hard disk,
you can say
FILES (instead of SHELL "dir /w").To delete JOE.BAS from your hard disk,
you can say
KILL "joe.bas" (instead of SHELL "del joe.bas").To change the name JOE.BAS to FRED.BAS,
you can say
NAME "joe.bas" AS "fred.bas" (instead of SHELL "rename joe.bas fred.bas").ON ERROR GOTO
You can improve the way that the computer handles errors.
Errors in a simple program
Here’s a simple program that divides two numbers and prints their quotient:
CLS
INPUT "What's your favorite number"; a
INPUT "What's another favorite number"; b
PRINT "The first number divided by the second is"; a / b
The program works for most numbers. But when the computer tries to divide, the computer will gripe if b is 0 (since you can’t divide by 0) or if the quotient’s too big to be a single-precision real number. (For example, if you try dividing 1E38 by .1, the answer is supposed to be 1E39; but the computer will gripe that the answer is too big for the computer to handle, since the biggest permissible single-precision real number is 3.402823E38.)
If b is 0, the computer will print this error message:
Division by zero
If the quotient’s too big to be a single-precision real number, the computer will print this error message:
Overflow
When the computer prints one of those error messages, the computer stops running the program and shows you the blue screen.
That confuses beginners! If a beginner tries to run your program and sees the computer say "Division by zero" or "Overflow" on a blue screen, the beginner might not understand what the computer means and might not understand what to do next.
Improved error-handling
Instead of letting the computer say "Division by zero" or "Overflow", let’s make the computer print this easier-to-understand message —
I can't handle that pair of numbers.
Please pick a different pair of numbers instead.
and then let the human type a new pair of numbers.
To do that, put these lines at the bottom of your program —
PRINT "I can't handle that pair of numbers."
PRINT "Please pick a different pair of numbers instead."
and tell the computer to do those lines whenever an error occurs in computing the quotient.
Here’s how:
CLS
10 INPUT "What's your favorite number"; a
INPUT "What's another favorite number"; b
ON ERROR GOTO 1000
quotient = a / b
ON ERROR GOTO 0
PRINT "The first number divided by the second is"; quotient
END
1000 PRINT "I can't handle that pair of numbers."
PRINT "Please pick a different pair of numbers instead."
RESUME 10
In that program, the source of the error (a / b) is isolated: it’s made into a separate line (quotient = a / b). Above that line, say ON ERROR GOTO 1000; below that line, say ON ERROR GOTO 0. The ON ERROR GOTO 1000 means: if an error occurs in the indented line underneath, go to line 1000. Line 1000 is the beginning of the
error-handling routine. The error-handling routine says that when an error occurs, print this —I can't handle that pair of numbers.
Please pick a different pair of numbers instead.
then print a blank line and then RESUME the program at line 10, which makes the computer ask again "What’s your favorite number?"
Remember:
The bottom line of the error-handling routine should say RESUME.
The bottom line of the rest of the program should say END.
"ON ERROR GOTO 1000" should be paired with "ON ERROR GOTO 0".
"ON ERROR GOTO 1000" means "Henceforth, if an error ever occurs, GOTO line 1000."
"ON ERROR GOTO 0" means "Henceforth, if an error ever occurs, go nowhere; just process the error normally."
In that program, the bottom four lines are called the
error-handling routine or error handler or error trap. Making the computer go to the error trap is called trapping the error.Error numbers
Besides "Division by zero" and "Overflow", there are many other errors that a program can make. Each error has a code number:
Code #
Message1 NEXT without FOR
2 Syntax error
3 RETURN without GOSUB
4 Out of DATA
5 Illegal function call
6 Overflow
7 Out of memory
8 Label not defined
9 Subscript out of range
10 Duplicate definition
11 Division by zero
12 Illegal in direct mode
13 Type mismatch
14 Out of string space
16 String formula too complex
17 Cannot continue
18 Function not defined
19 No RESUME
20 RESUME without error
24 Device timeout
25 Device fault
26 FOR without NEXT
27 Out of paper
29 WHILE without WEND
30 WEND without WHILE
33 Duplicate label
35 Subprogram not defined
37 Argument-count mismatch
38 Array not defined
40 Variable required
50 FIELD overflow
51 Internal error
52 Bad file name or number
53 File not found
54 Bad file mode
55 File already open
56 FIELD statement active
57 Device I/O error
58 File already exists
59 Bad record length
61 Disk full
62 Input past end of file
63 Bad record number
64 Bad file name
67 Too many files
68 Device unavailable
69 Communication-buffer overflow
70 Permission denied
71 Disk not ready
72 Disk-media error
73 Advanced feature unavailable
74 Rename across disks
75 Path/File access error
76 Path not found
Whenever the computer detects an error, the computer makes ERR be the error-code number. For example, when the computer detects an Overflow error, the computer makes ERR be 6. If you say —
PRINT ERR
the computer will print 6.
You can use ERR in the error-handling routine. For example, here’s how to say "if the error was Overflow":
IF ERR = 6 THEN
At the bottom of the error-handling routine, the RESUME line automatically makes the computer reset ERR to 0, so the computer is prepared to handle future errors.
Here’s the sophisticated way to divide two numbers:
CLS
10 INPUT "What's your favorite number"; a
INPUT "What's another favorite number"; b
ON ERROR GOTO 1000
quotient = a / b
ON ERROR GOTO 0
PRINT "The first number divided by the second is"; quotient
END
1000 SELECT CASE ERR
CASE 11
PRINT "I can't divide by zero."
CASE 6
PRINT "The answer is too big for me to handle."
CASE ELSE
PRINT "I'm having difficulty."
END SELECT
PRINT "Please pick a different pair of numbers instead."
RESUME 10
In that program, the error-handling routine says:
If the error-code number is 11 (which means "Division by zero"), print "I can’t divide by zero."
If the error-code number is 6 ("Overflow"), print "The answer is too big for me to handle."
If the error-code number is otherwise, print "I’m having difficulty."
After printing one of those error messages, the computer will print "Please pick a different pair of numbers instead". Then the computer will do RESUME 10, which goes back to line 10 and also resets ERR to 0.
Unnumbered RESUME
If you don’t put any number after RESUME, the computer will go back to the line that contained the error.
If you say RESUME NEXT, the computer will go to the line underneath the line that contained the error. To make RESUME NEXT work properly, the line that contained the error should consists of just one statement (instead of statements separated by colons).
Memory cells
The computer’s memory chips consist of many
memory cells. Each cell holds an integer from 0 to 255. For example, cell #49837 might hold the integer 139.Segments
The first 65536 cells (cell #0 through cell #65535) form
segment 0. The next 65536 cells are in the next segment, which is called segment 16. The next 65536 cells are in segment 32; the next 65536 cells are in segment 48; the next 65536 cells are in segment 64; the next 65536 cells are in segment 80; etc. Notice that the segment numbers are multiples of 16.Within each segment, the cells are numbered from 0 to 65535. For example, the first cell in segment 16 is called "cell #0 of segment 16"; the next cell in segment 16 is called "cell #1 of segment 16"; the last cell in segment 16 is called "cell #65535 of segment 16".
PEEK
This program finds out what number’s in cell #49837 of segment 0:
CLS
DEF SEG = 0
PRINT PEEK(49837)
The "DEF SEG = 0" tells the computer to use the memory’s main SEGment, which is SEGment 0. The bottom line makes the computer PEEK at cell #49837, find the number in that cell, and print that number on your screen. The number it prints will be an integer from 0 to 255. For example, it might be 139.
When dealing with memory cells, make sure your program begins with a DEF SEG line, to tell the computer which segment to look in. If you forget to say DEF SEG, the computer will look in its "favorite" segment, which is not segment 0.
Cell #1047
In cell #1047 of segment 0, the computer puts a number that describes the state of your keyboard. The computer computes that number by using this chart:
Start at 0.
Add 1 if the right SHIFT key is being pressed now.
Add 2 if the left SHIFT key is being pressed now.
Add 4 if either Ctrl key is being pressed now.
Add 8 if either Alt key is being pressed now.
Add 16 if the SCROLL LOCK is turned on (by an earlier keypress).
Add 32 if the NUM LOCK is turned on (by an earlier keypress).
Add 64 if the CAPS LOCK is turned on (by an earlier keypress).
Add 128 if the INSERT is turned on (by an earlier keypress).
For example, if NUM LOCK and INSERT are turned on, that cell contains 32+128, which is 160.
This program shows you what’s in that cell:
CLS
DEF SEG = 0
PRINT PEEK(1047)
For example, if NUM LOCK and INSERT are turned on, the computer will print 160.
Loop
This program peeks at cell #1047 repeatedly:CLS
DEF SEG = 0
DO
PRINT PEEK(1047)
LOOP
If the NUM LOCK and INSERT keys are turned on, the computer will repeatedly print 160, like this:
160
160
160
etc.
While that program keeps running, try pressing the SHIFT, Ctrl, Alt, SCROLL LOCK, NUM LOCK, CAPS LOCK, and INSERT keys. Each time you press any of those keys, the number 160 will change to a different number.
Cell #1048
In cell #1048 of segment 0, the computer puts a supplementary number describing your keyboard’s state. That number is computed as follows:
Start at 0.
Add 1 if the left Ctrl key is being pressed now.
Add 2 if the left Alt key is being pressed now.
Add 16 if the SCROLL LOCK key is being pressed now.
Add 32 if the NUM LOCK key is being pressed now.
Add 64 if the CAPS LOCK key is being pressed now.
Add 128 if the INSERT key is being pressed now.
This program shows you what’s in both of the keyboard-state cells:
CLS
DEF SEG = 0
DO
PRINT PEEK(1047), PEEK(1048)
LOOP
While running that program, try pressing the Ctrl, Alt, SCROLL LOCK, NUM LOCK, CAPS LOCK, and INSERT keys. Watch how the numbers on the screen change!
That’s how computers work: in memory cells, the computer stores code numbers that represent what you and the computer are doing.
POKE
Let’s make the computer turn on the CAPS LOCK (so all your typing will be capitalized), NUM LOCK (so typing on the numeric keypad will create numbers instead of arrows), and INSERT (so typing in the middle of a document will make the other words move out of the way).
In cell #1047, the code number for NUM LOCK is 32, CAPS LOCK is 64, and INSERT is 128, so the code number for their combination is 32+64+128, which is 224. To turn on CAPS LOCK, NUM LOCK, and INSERT, just put the code number 224 into cell #1047. Here’s how:
CLS
DEF SEG = 0
POKE 1047, 224
In that program, "POKE 1047, 224" means "put, into cell #1047, the number 224".
Danger
Poking into cell 1047 or 1048 is safe (if you say DEF SEG = 0), but poking into other cells can be dangerous, since some of those cells are where the computer stores notes about your program, operating system, disks, and other devices. Poking wrong info into those cells can wreck your program, operating system, and the info on your disks.