issue #4

By Thav

A lot of people have had problems with memory in qbasic. Everyone has at least once in their programming career. Memory problems can be fixed if you know what could possibly be causing the problem. A lot of people have asked me questions about "Out of stack space" and "Out of memory" errors. This short article will clarify some things about these two errors.

Your program will use stack space, there's no way of getting around this. Every program that you execute has a runtime stack. This is where all of the program information is stored. No variables or data is stored in this stack, but there is a bit of information that is pushed onto it every time you run your program.

An entry on the runtime stack is called an Activation Record. An activation record is pushed onto the stack every time your program is run or calls a function or sub. Activation records contain information used by the computer to pass variables and to return to the right place. An activation record contains information about the function you call: a return address, any paramaters, and any return variables. A return address is something used by the computer to control program flow. Think of this as a line number, say you call your sub Compute on line 156, an activation record is pushed onto the stack, with a return address of 157 in it. So when Compute is done running, your program will return to line 157. Let's say Compute has some paramaters: Compute (first%, last%). First% and Last% will also be stored in the activation record. Return variables are also stored in the activation record. When Compute is called, space is allocated for a return variable. When Compute is done, it's activation record is popped off the runtime stack and that variable is returned. This is basically how a runtime stack works. It may not be exactly, because it's been a while since i've looked at the runtime stack. When you run your program and get an "Out of stack space" error, you have blown the stack. You blow the stack when you try to push another record on the stack and there's no more room. The way you can do this is to have a recursive function, a function that keeps calling itself, that doesn't have an exit condition.

SUB BlowStack()
CALL BlowStack()

That little code will effectively blow the stack. It keeps calling itself and doesn't have an exit condition, so an activation record will be pushed on the stack until the program runs out of space. The easiest way to keep a recursive function from using up all the stack, is to not have them. So unless you really know how to work recursive functions, I'd suggest staying away from them.

There are a few rules to follow to avoid out of stack space errors:

I've never needed more than the default stack space. You can always use CLEAR to make more room for the stack. Just remember, no variables go on the stack, so if you get Out Of Memory errors, using CLEAR won't solve that.

Now for a stint about variables. Aaah variables, the best invention since fire. But how much do we really know about variables. Look out, because I'm about to spill all the info I know about variables.

There's the basic definition of variables, but how can you use them more effectively? Depends on what you want to do. Here's some fairly advanced data structures:

These guys are fun. They're basically a collection of variables under a certain name. For example: DIM scores(0 to 100) AS INTEGER will give you 100 integers. The way you access each of these variables is by subscripting them. scores(57) will give you the 57th score in your array. You can use another integer variable inside the subscript. scores(topscore) would give you the entry that corresponds with topscore. The variable inside the subscript has to be an integer by convention.

Commonly refered to as records, typedefs (in C) or classes(in C++). They are a collection of different types of variables under one name. Here's an example:

TYPE PersonalInfoType
  theName as string * 10
  age as integer
  address1 as string * 20
  address2 as string * 20

This is a collection of data all rolled into one name. They are especially nice for having a collection of global data. Here's a snippet on how you use a type:

DIM info AS PersonalInfoType

info.theName = "John"
info.age = 23

Pretty easy huh? Well, you can add those into arrays and have all kinds of fun.

DIM info(3000) as PersonalInfoType

Now we have 3000 personal info type thingies. How can we access each part? info(55).theName = "Jane". Just like accessing an array and a type at the same time.

Now that I've told you a bunch of neat stuff that you probably knew, how can you use this to your advantage? There are a few techniques that I use to expand the use of my variables:

String * 1. Ahh the byte. Such a use for it. I've found these to be useful for ASCII flags. using an ascii character set, you can have roughly 255 different values for it. You can also use them if you only have a number from 0 to 255. Let's say you have some file format that uses numbers in this range. Instead of using a 2-byte integer, you can use a String *1, and just use ASC(byte) to get it's value. Using this technique is good for bsaving arrays and such.

Types. I use these alot when I have a lot of data I want to use globally. For instance, in Medallion, I have a global data type called GameInfo, which contains the current map, the old map, and other values pertaining to the world. I also have one for the character, and other parts of the game. It makes it easier than typing DIM SHARED variable AS type...

Well, I guess that's about it for this article. There are a lot of other topics I could cover, but my time is pressed. I hope you enjoyed and got some information out of this. Good Luck.

Raul Carolus

Back to Top

This tutorial originally appeared in QBasic: The Magazine Issue 1.