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