QBasic - Step By Step :: Section 4
Author: Mike Ware
Website: [warebiz] :: "The Programmer's Domain" - http://warebiz.tripod.com
Email: warebiz@yahoo.com
Copyright © 2002 Michael Shawn Ware, All Rights Reserved.


You are here --> [Section 4 :: Using Modules]

"Jump To Articles"
    --> SUB Procedures
    --> Passing Values to SUB Procedures
    --> Local Variables
    --> Passing Variables by Reference Vs. Passing Variables by Value
    --> Advantages of Using Modules


Sub Procedures

When modularizing a program, you are essentially dividing a program into subprograms or procedures. The subprograms or procedures have a particular task to perform for the program's overall purpose. In QBasic, there are two types of subprograms: SUB procedures and Function procedures. In this article, I will cover SUB procedures. I cover Functions in later articles. For now, you need to know that a SUB procedure is essentially a program within a program designed to perform a specific task. When using SUB procedures, you are basically breaking down a program into logical steps. This makes your program code easier to understand and follow.

A SUB procedure begins with the keyword SUB followed by the name of the procedure that the programmer specifies. The same rules apply for naming SUB procedures as they do for naming variables. After the name, a parameter list may follow (more on this later), and then the body of the procedure. After the body, the keywords END SUB mark the end of the procedure.

After you write code for a procedure, you may then use the procedure wherever you like in the program by "calling" upon it using a CALL statement. This is done by simply placing CALL along with the name of the procedure you wish to execute in your program where you want it to be executed. You can call a procedure anywhere in a program and even in other SUB procedures.

NOTE: A driver is a program where the primary purpose is just to call procedures (the main module contains only calls to SUB procedures); the procedures perform all necessary program operations.

Coding SUB Procedures
Each module, including the main module, in QBasic is given a seperate window for coding purposes. To enter a new procedure, simply type SUB and the name you wish to give the procedure in your compiler and hit enter. A new window will appear with the procedure's name, and all you have to do is specify the code for the procedure's body. You can then toggle back and forth among modules by pressing F2 and selecting your destination. For example, the following is a simple SUB procedure designed to print a dividing line. Instead of writing code for the dividing line in your program whenever you need to use it, you can simply call this procedure:


SUB dividingLine

REM ***** This procedure simply displays a dividing line to screen for formatting output purposes. *****

PRINT
PRINT "------------------------------------------------------------"
PRINT

END SUB


Passing Values to SUB Procedures

SUB procedures also have the ability to transfer or pass the value of variables from one module to the next through the use of arguments and parameters. This is handy when you need to send data to a procedure to perform a task that depends on the data. An argument is placed in parentheses in the CALL statement and allows a value to be passed from the current module to the calling module. A parameter is placed in parentheses after a SUB procedure's name. When the procedure is called, the value of the argument is sent to the corresponding parameter that it matches up with in the SUB procedure parameter list. That parameter will then hold the value of the argument for use in the procedure.

NOTE: When passing arguments, the parameter list and argument list of the procedure must match in number of arguments and also data types. This means that you can't pass a numeric variable to a character string variable, or vice versa. The lists must match data types. However, the argument name doesn't have to match the corresponding paramter name. The following is a simple SUB procedure demonstrating how to pass variables to a procedure (notice how it calls our previously mentioned dividingLine Procedure):


SUB displayResults(stuName$, gpa)

REM ***** This procedure displays a student's name and GPA average. *****

CALL dividingLine

PRINT "Student Name: "; stuName$
PRINT "GPA average: "; gpa

END SUB


Whenever you create a SUB procedure and then save your program, your QBasic compiler will automatically place a DECLARE statement at the beginning of your program for the procedure, and you will see the DECLARE statement as long as you still use the SUB in your program. A DECLARE statement simply tells the compiler the name and data types of parameters of the procedure. All SUB procedures will be given a different DECLARE statement. If you edit a procedure's parameter list, you must also edit the DECLARE statement or simply delete the DECLARE statement forcing the compiler to create a new one.

Local Variables

When using modules in your programs, you will most likely start to use local variables. A local variable is only used in a specific procedure (the one it is in) and only exists while the procedure is being executed. Because it is "local" to the procedure, no outside modules have access to it or even know its value. Local variables have use only for the procedure it is contained in, and they serve to protect a program from accidental changes to a variable. For example, consider the following SUB procedure. In this SUB, the local variable is the variable named average:


SUB getAverage(num1, num2, num3)

REM ***** This procedure calculates and displays the average of three numeric values. *****

average = (num1 + num2 + num3) / 3

PRINT
PRINT "The average of the three values is: "; average
PRINT

END SUB


Passing Variables by Reference Vs. Passing Variables by Value

When passing a variable by reference, the memory address of the argument is actually passed to the parameter of a procedure; this allows any changes that may occur to the variable during execution of the procedure to be sent back to the calling module. When passing by value, the parameter gets a "copy" of the argument and any changes done to the variable do not get sent back to the calling module. When passing constants and expressions to a procedure, they are automatically passed by value. If you want to pass a variable by value, simply place the variable in parentheses in both the CALL and SUB lists. For example, consider the following SUB where score is passed by value:


SUB displayResults((score), stuName$, schoolName$)

PRINT
PRINT "STUDENT: "; stuName$
PRINT "SCHOOL NAME: "; schoolName$
PRINT "SCORE: "; score
PRINT

score = 0.0

END SUB


The question is whether or not the value of score will equal 0.0 after the procedure is done execution. Since score was passed by value, it will not have a value of 0.0 when execution goes back to the calling module.

Advantages of Using Modules

There are many advantages of using modules in your programs, especially for large and complex programs. Procedures can be called infinitely many times. This cuts back on code for tasks needed more than once in a program. Also, procedures can easily be transfered from one program to the next.Procedures break down a program into logical steps for easier understanding of code and flow of a program. It is also much easier to debug and test for errors because errors will appear in the particular error-filled module. Finally, by using procedures, it is much easier to modify the program in the future.

The following is a complete program demonstrating material covered in sections 1 to 4:


\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

DECLARE SUB GetData (cardNumber!, nme$, address$, title$, bookType!, daysOverdue!)
DECLARE SUB GetFine (bookType!, daysOverdue!, fine!)
DECLARE SUB DisplayResults (cardNumber!, nme$, address$, title$, fine!)


REM **************************************************
REM This program simply acts as a computerized
REM library assitant designed to caculate the
REM total cost a patron owes for an over-due item.
REM **************************************************

CLS

CALL GetData(cardNumber, nme$, address$, title$, bookType, daysOverdue)

CALL GetFine(bookType, daysOverdue, fine)

CALL DisplayResults(cardNumber, nme$, address$, title$, fine)

END

SUB DisplayResults (cardNumber, nme$, address$, title$, fine)

CLS
Format$ = "\              \          $$###.##"
PRINT
PRINT TAB(29); "-------------------"
PRINT TAB(30); "Shawshank Library"
PRINT TAB(29); "-------------------"
PRINT
PRINT "Library Card Number:"; TAB(29); cardNumber
PRINT "Patron's Name:"; TAB(30); nme$
PRINT "Address:"; TAB(30); address$
PRINT "Item's Title:"; TAB(30); title$
PRINT USING Format$; "Amount of fine:"; fine

END SUB

SUB GetData (cardNumber, nme$, address$, title$, bookType, daysOverdue)

PRINT
INPUT "Enter the patron's card number (####): ", cardNumber
INPUT "Enter the patron's name: ", nme$
INPUT "Enter the patron's address: ", address$
INPUT "Enter the book's title: ", title$
PRINT
PRINT TAB(25); "1 : Paperback - Regular"
PRINT TAB(25); "2 : Paperback - Bestseller"
PRINT TAB(25); "3 : Magazine"
PRINT TAB(25); "4 : Hardcover Book"
PRINT
INPUT "Enter number corresponding to type of book (1 - 4): ", bookType
PRINT
INPUT "Enter the number of days overdue: ", daysOverdue

END SUB

SUB GetFine (bookType, daysOverdue, fine)

rate1 = .2
rate2 = .5
rate3 = .25
rate4 = .3

SELECT CASE bookType
   CASE 1
      fine = rate1 * daysOverdue
      IF fine > 5 THEN
         fine = 5
      END IF
   CASE 2
      fine = rate2 * daysOverdue
      IF fine > 10 THEN
         fine = 10
      END IF
   CASE 3
      fine = rate3 * daysOverdue
      IF fine > 4 THEN
         fine = 4
      END IF
   CASE 4
      fine = rate4 * daysOverdue
      IF fine > 20 THEN
         fine = 20
      END IF
END SELECT

END SUB

////////////////////////////////////////////////////////////////////////////////


In section 3, we discovered how to control execution with control structures. In the next section, you will be introduced to controlling the flow or execution of a program with loops. Read on for more...

Move on to next set of topics: Section 5 - Controlling Execution With Loops

Back to Top