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