
HomePage | Optical Illusions | War Stories | QBasic | Dads Navy Days | Bristol | Bristol, USA | Bristol, Canada | Terre Haute | Miscellany | Web Stuff | About Ray | Site Map | Site Search | Messages | Credits | Links | Web Rings
QBasic | Errors | 40lb Weight | Bits | Chance | Colours | Dates | Delays | File Dialog | Files | Input | Matching | Menus | Mouse | Numbers | SeqNo | SIRDS | Sorts | Text | Timer | DLoads
Programming Errors:
Everybody makes mistakes when programming, from simple "oops, typed that wrong." or "oh yeah, forgot the syntax for that." to "What the hell's going on in there?"
Errors are almost inevitable, and fall into one of three main camps :-
Typos - the misspelling of a word or command, using the incorrect syntax. For instance using PRJNT instead of PRINT. QBasic upper cases all its keywords so you can usually spot these straight away. It also checks for errors in syntax eg. MID$("ABC",2) gives an error. This is because Mid$ expects a variable or string without the quotes and because it expects another variable.
Runtime - The spelling and syntax is correct but on running the program it stops with an error message, usually because you or the user have forgotten something. An example of this is trying to open a non-existant file for editing or trying to append text to a file that already exists without opening it for both READ and WRITE.
Logic - One of the hardest to remedy. The spelling and syntax is correct, no runtime errors are reported but the program does not behave as it should. It may be something relatively simple like multiplying two variables when they should have been added, or not setting a variable properly so that it's value isn't what you think it should be. In other cases it may be that your logic for a particular piece of code is wrong. Sometimes your logic may be right but the way you implemented it is wrong, so that your program becomes convoluted and takes far longer to complete a task than it should.
Example 1
A little while ago I wanted to test some sort algorithms. The code I wanted to test came with some sample data but was a bit limited having only 40 odd variables. I wanted to test them using something more akin to a real world test. I wrote a program that produced some files, one completely sorted but 'upsidedown', two nearly sorted but with with some numbers transposed and one completely random.
The first couple was fine but the completely random one didn't work at all well. My original logic for this piece of code was this :-
Generate a random number between 1 and 30,000
Check this number wasn't already in an array
If it was not already present put this number into the array and write it to disk
If it was already present generate another random number and check again
Continue the above until the numbers 1 to 30,000 were generated in a random order.
The actual code to accomplish this was :
RANDOMIZE TIMER
For Count = 1 to 30000
DO
Number = (RND * 30000) + 1
FOR Counter = 1 TO Count
IF Number = NumArray(Counter) THEN EXIT FOR
NEXT Counter
LOOP UNTIL Counter = Count + 1
NumArray(Count) = Number
Print #1, NumArray(Counter)
Next Count
Nothing much wrong with that - at first glance. It starts quite quickly - the array starts off quite small but as more numbers are generated it has to do more and more checking. Not only that but with less choice in the number of random numbers that can be made before it meets a match this program starts to run very very slowly. In fact, after 26 hours it still had only generated 28,000 different numbers and I had to stop the program and have a rethink.
I changed the logic slightly so that :-
Create an array that contains the numbers 1 to 30,000 in order
Generate a random number between 1 and the length of the array (initially 30,000)
Take that array element and write it to a file
From the number generated to the end of the array shuffle the numbers upwards by one
Decrease the range of the random number by one (at each step through the loop)
Continue until all 30,000 elements of the array have been written to disk
The code now becomes :-
'Make an array of completely sorted numbers
FOR Count = 1 TO 30000
NumArray(Count) = Count
NEXT Count
RANDOMIZE TIMER
FOR COUNT = 1 TO 30000
Number = (RND * (30001 - Count)) + 1
PRINT #1, NumArray(Number)
FOR Counter = Number TO 30000 - Count
NumArray(Counter) = NumArray(Counter + 1)
NEXT Counter
NEXT COUNT
This code starts off quickly and gets faster as the array gets smaller. A few minutes later I had 30,000 randomly generated numbers in the range 1 - 30,000. A vast improvement of having to wait for over 26 hours when it didn't even finish.
User Errors:
As well as the programming errors, a programmer should also think of errors that a user might make. In short, to make his programs bullet-proof. A user may type a file name for an output file, do they know that a file of the same name may already exist? Do they want to overwrite it or be given the chance to choose a new file name? If you've asked a user to input something, what happens if they've given you a number larger than 32,676 and you've only provided enough storage for an integer. What happens if your program expects a number and they type in a character or vica versa?
I've called this chapter User Errors, this a mistake, errors of this sort should be anticipated and allowed for by the programmer.
The following program, FileErr.bas, tests whether a file (C:\rayray.ray) exists, if it does not then it creates it, then tests for it again. The file is deleted on exiting the program.
'FileErr Ray Thomas May 2000
'A program to demonstrate how to test if a file exists
OutFile = FREEFILE
ON ERROR GOTO Err1
CLS
PRINT
OPEN "C:\rayray.ray" FOR INPUT ACCESS READ LOCK READ WRITE AS OutFile
CLOSE
'If, by some fluke, the file already exists I'm leaving
'******************************************************
PRINT "The file C:\rayray.ray already exists, exiting program"
END
NoFile1: '*** Return to here after the initial error report ***
PRINT
PRINT "Press any key to create it ..."
PRINT
DO
LOOP UNTIL INKEY$ <> ""
OPEN "C:\rayray.ray" FOR OUTPUT ACCESS WRITE LOCK READ WRITE AS OutFile
PRINT #OutFile, "This file is for test purposes only"
PRINT #OutFile, "and can be safely deleted."
CLOSE
PRINT
PRINT "The file now exists ..."
PRINT
PRINT "Press any key to check that it does !"
PRINT
PRINT
DO
LOOP UNTIL INKEY$ <> ""
ON ERROR GOTO Err2
OPEN "C:\rayray.ray" FOR INPUT ACCESS READ LOCK READ WRITE AS OutFile
CLOSE
PRINT "The file we've written, does indeed exist,"
PRINT "If it didn't then this message wouldn't show !"
PRINT "It is here that the user can be asked whether they want to change"
PRINT "a file name, overwrite one, exit the program or whatever."
PRINT
PRINT
PRINT "Press any key to delete C:\rayray.ray and end the program ..."
DO
LOOP UNTIL INKEY$ <> ""
KILL "C:\rayray.ray"
END
Err1:
IF ERR = 53 THEN
PRINT
PRINT "It's OK to create C:\rayray.ray, it does not already exist."
PRINT "We know this because the error code returned was"; ERR
RESUME NoFile1:
END IF
Err2:
IF ERR = 53 THEN
PRINT
PRINT "mmm, something wrong here, we just wrote the file"
PRINT "and so we shouldn't see this message !"
PRINT "The error code returned was"; ERR
PRINT
PRINT "Exiting program ..."
END
END IF
Notice that the program only tests for Error 53 - File not found. The ON ERROR GOTO routine can take care of any of the 76 run time errors that can stop a program from working, in the example above the returned error code can give information back to the program.
Pebe wrote a nice little 6 line piece of code that will does a similar thing but in a different way :-
SUB check4file(filename,a%) OPEN (filename) FOR APPEND AS #1 IF LOF(1)=0 THEN a%=0 ELSE a%=1 CLOSE filename IF a%=0 THEN KILL (filename) END SUB
When I was writing this I tried with other types of error codes, especially those of variable overflow, Error 6. QBasic has it's own handler for this, the rather inelegant "redo from start" message, which if you've gone to the trouble of designing a nice screen, is certainly going to mess it up for you.
To see what I mean use this program snippet :-
DIM Num AS INTEGER CLS PRINT ON ERROR GOTO InErr INPUT ; "Type in a number bigger than 32,767 (or a letter) " , Num END InErr: PRINT PRINT "Bet you never get to see this message." RESUME NEXT
A way round this problem is to dump INPUT or INPUT$ altogether and write your own verification code, trapping key presses, by using INKEY$ instead. I've written one that you can adapt, it can be found in Input.
QBasic | Errors | 40lb Weight | Bits | Chance | Colours | Dates | Delays | File Dialog | Files | Input | Matching | Menus | Mouse | Numbers | SeqNo | SIRDS | Sorts | Text | Timer | DLoads
HomePage | Optical Illusions | War Stories | QBasic | Dads Navy Days | Bristol | Bristol, USA | Bristol, Canada | Terre Haute | Miscellany | Web Stuff | About Ray | Site Map | Site Search | Messages | Credits | Links | Web Rings