Qbasic Tutorial : Learn Qbasic in a fast, simple,short, and intuitive way. Honest Effort Required.

--- Qbasic ---

CHAPTER 9

Data Types, Record, and RANDOM ACCESS FILE


DATA TYPES

There are many data types in Qbasic :

  1. integer
    An integer occupies 16 bits (1 bit may store 0 or 1, and 8 bits = 1 byte), Hence maximum value an integer can hold = 2^16 = 65536, or +/- 32767.
  2. long
    long = long interger, it occupies 32 bits. Hence its maximum value is 2^32 or +/- 2^31 - 1
  3. single
    single = single precision real number, it occupies 32 bits, and it can represent a real number to 7 significant figures.
  4. double
    double = double precision real number, it occupies 64 bits, and it can represent a real number up to 16 significant figures.
  5. string
    String consists of several bytes. String must be enclosed within quotation marks, e.g. a$ = "Hong Kong and Kowloon".

If we do not declare what data type a variable takes, Qbasic would assume that it is a single precision number.

Exercise : How many bytes are there in integer, long, single, double ? ( 1 byte = 8 bits)

Ans : integer 2 bytes ; long 4 bytes; single 4 bytes; double 8 bytes.


DECLARATION OF DATA TYPES

There are 3 ways to declare data type of variables :

  1. By the first letter of the variable name :
    defint i-n
    Here defint (=define integer) is a Qbasic keyword. It means that if that variable name begins with letters {i,j,k,l,n}, that variable is to be regarded as integer. Hence variables "icount, linecount, mpage, nrow ... " would all be treated as integers.

    defdbl a-h,o-z
    Here defdbl (= define double) is also a Qbasic keyword. Here all variables whose name begin with a to h, or o to z are to be regarded as double precision numbers. e.g. xmean, std, .... are regarded by Qbasic as double precision numbers.

    defstr (=define string), deflng (=define long), defsng (=define single) have similar usage as above.

  2. With a special character at the end of the variable name.
    1. count%, row%, column% ....
      % informs the computer that they are integers, hence count%, row%, column% .... are all integer.
    2. count&, row&, column& ....
      & informs the computer that they are long integer, hence count&, row&, column& ... are all long integers.
    3. mean!, std!, deviation! ......
      ! informs the computer that they are single precision real number, hence mean!, std!, deviation! ... are all single precision numbers.
    4. mean#, std#, deviation# .....
      # that they are double precision real number, hence mean#, std#, deviation# .... are all double precision numbers.
    5. name$, telephone$, mark$ .....
      $ stands for string. Hence name$, telephone$, mark$ ... are all string.


  3. With the use of dimension statement. Previously, we use " dim " to declare arrays. But dimension statement may also be used to declare variable types, e.g.
    dim n as integer
    dim a(4,5,3) as long
    dim xmean as single
    dim b(3,4) as double
    dim name as string
    dim icount as integer, linecount as integer, nrow as integer
    Note : it is rather clumsy to declare variables in Qbasic. Pascal and C are better in this aspect, e.g.

    in C
    int icount, linecount, nrow;
    or in Pascal
    var
    icount, linecount, nrow : integer;
    If someone would implement in Qbasic
    dim icount, linecount, nrow as integer
    to mean icount, linecount, nrow are all integers, then that would be more convenient. In reality, if we declare in this way, Qbasic would only regard nrow as integer, the rest ( icount, linecount ) would all be regarded as single.

RECORD

Suppose we wish to create a master file for the students. We wish to record down their name, age, sex, tel (=telephone number). First we define RECORD type :


type strecord
sname as string*30
age as integer
sex as string*1
tel as string*10
activeflag as integer
end type
dim ss as strecord

Note :

  1. Because "name" is a Qbasic keyword, therefore we have used "sname" instead.

  2. TYPE ....
    .... as ...
    .... as ...
    END TYPE
    TYPE statement "TYPE ...... END TYPE" is used to define new data types, apart from the usual integer, long, single, double, string.
    After the "type statement", we use "dimension statement to declare which variables are of this type, e.g.
    dim ss as strecord
    dim tt as strecord
    then both ss, tt are of the record type defined above.

  3. Exercise : Find out how many bytes the variable "ss" defined above will take.
    Ans : 30 + 2 + 1 + 10 + 2 = 45 bytes.

  4. Suppose we now have
    TYPE stockrecord
    sname as string*100
    location as string*50
    price as double
    supplier as long
    quantity as long
    reorder as long
    END TYPE
    DIM st as stockrecord

    Exercise : compute how many bytes "st" will take.
    Ans : 100 + 50 + 8 + 4 + 4 + 4 = 170 bytes.

  5. len(..) is a Qbasic built-in function. Its main use is to find out the length of strings, e.g.
    print len("Hong Kong")
    then the computer will print : 9 ( as "Hong Kong" is 9 bytes long).
    But len(..) may also be used on record variables. It will print out the number of bytes that variable will occupy, e.g.
    print len(st)
    Then computer will print : 170 ( the record variable "st" is 170 bytes long).

  6. Exercise : Find out the meaning of the following Qbasic built-in string functions, with the help of online manual (Shift + F1) :
    1. mid$(a$,n,m)
    2. left$(a$,n)
    3. right$(a$,n)
    4. lcase$(a$)
    5. ucase$(a$)
    6. instr(a$, b$)


  7. Exercise : suppose you have a random files of 1000 records, and the length of one record is 170 bytes. As the file is a "random file" we may access the records randomly (the Qbasic statements to do that will be explained later). Now suppose you find that one record is no longer used, and you want to delete it, how would you do that?
    Ans : It is not easy to delete a record from a random file. Hence the usual practice is to define another variable within the record, e.g. in the "strecord", we have
    activeflag as integer
    When the record is active, we set activeflag to 1. When it is no longer needed, and we wish to delete it, we set activeflag to 0. Hence a check of this variable will show whether it has been deleted or not.


Here is a program to create a master file.


DEFLNG I-N
DEFDBL A-H, O-Z

TYPE strecord
    sname AS STRING * 30
    age AS INTEGER
    sex AS STRING * 1
    tel AS STRING * 10
    activeflag AS INTEGER
END TYPE

DIM ss AS strecord

CLS 0
mrecordlength = LEN(ss)
PRINT "Record Length = "; mrecordlength

OPEN "c:\test\q9_mas" FOR RANDOM AS #1 LEN = mrecordlength

irecord = 1

L20:
    PRINT
    INPUT "Name "; ss.sname
   
    IF LEFT$(ss.sname, 4) = "****" THEN        (NOTE : because sname is 30 bytes long,
        CLOSE 1                                        we compare only the leftmost
        END                                            4 bytes.  Qbasic would reqard
    END IF                                             2 strings of different lengths unequal,
                                                       even if their non-blank parts are
L40:                                                   equal.)
    INPUT "Age"; ss.age
    IF ss.age > 1000 OR ss.age < 0 THEN        (NOTE : this is for data validation.
         SOUND 2000, 5                                 Data Validation must be carried
         GOTO L40                                      out to make the program ROBUST.
    END IF                                             There is a saying 
                                                       "Garbage in, Garbage out" )
L60:
    INPUT "Sex"; ss.sex
   
    ss.sex = LEFT$(ss.sex, 1)                  (NOTE : we only use 1 character for sex. )

    IF ss.sex = "m" THEN                       (NOTE : we change all lower case to upper
        ss.sex = "M"                                   case, hence M=male, F=female, and
    ELSEIF ss.sex = "f" THEN                           m, f would not be used.)
        ss.sex = "F"
    END IF

    IF NOT (ss.sex = "M" OR ss.sex = "F") THEN     (NOTE :  data validation procedure.)
         SOUND 2000, 5
         GOTO L60
    END IF

L80:
    INPUT "Telephone number "; ss.tel

    ss.activeflag = 1                         (NOTE : this means the record has not been
                                                      deleted.)
    PUT 1, irecord, ss
    irecord = irecord + 1
    GOTO L20

[Download Program]

Here is a program to read the above master file.

DEFLNG I-N
DEFDBL A-H, O-Z

TYPE strecord
    sname AS STRING * 30
    age AS INTEGER
    sex AS STRING * 1
    tel AS STRING * 10
    activeflag AS INTEGER
END TYPE

DIM ss AS strecord

PRINT LEN(ss)

OPEN "c:\test\q9_mas" FOR RANDOM AS #1 LEN = 45 
                                           (NOTE : it is advisable to put LEN=LEN(ss)
                                                   instead of LEN=45.
CLS 0
mrecord = LOF(1) / 45                      (NOTE : LOF(1) = length of file of file 1       
PRINT "Number of records = "; mrecord            LOF(n) is a Qbasic built-in function. 
                                                 no. of records in random file =
                                                   LOF(1) / LEN(ss) )
L20:
     INPUT "Enter record number (-999 = end) "; i       

     IF i = -999 THEN
        CLOSE 1
        END
     END IF

     IF NOT (i >= 1 AND i <= mrecord) THEN      (NOTE : record number starts from 1
          SOUND 1500, 5                                 to mrecord, hence we check               
          PRINT "Non-existent record"                   for  1 <= i <= mrecord.)
          GOTO L20
     END IF

     GET 1, i, ss
     PRINT
     PRINT USING "Name           : \         \"; ss.sname     (NOTE: \   \ length 
     PRINT USING "Age            : ##"; ss.age                  of string to be printed.
     PRINT USING "Sex            : !"; ss.sex                   ! = print only 1 c
     PRINT USING "Tel. No.       : \         \"; ss.tel             character for that
     PRINT USING "Active flag    : #"; ss.activeflag                string.)
     PRINT
     GOTO L20
CLOSE 1
END

[Download Program]

Note :

  1. Suppose we have two record variables, ss and tt , e.g.
    TYPE strecord
    ... as ...
    ... as ...
    END TYPE
    dim ss as strecord
    dim tt as strecord
    then "ss.sname, ss.sex, ss.tel, ss.activeflag" would distinguish them from
    "tt.sname, tt.sex, tt.tel, tt.activeflag"

  2. Exercise : write a program that prints out all students aged between 17 and 19.

Ans :


DEFLNG I-N
DEFDBL A-H, O-Z

TYPE strecord
    sname AS STRING * 30
    age AS INTEGER
    sex AS STRING * 1
    tel AS STRING * 10
    activeflag AS INTEGER
END TYPE

DIM ss AS strecord

OPEN "c:\test\q9_mas" FOR RANDOM AS #1 LEN = LEN(ss)
OPEN "c:\test\q9_out.txt" FOR OUTPUT AS #2

CLS 0
mrecord = LOF(1) / LEN(ss)
PRINT "Number of records = "; mrecord

PRINT #2, "THOSE STUDENTS WHO ARE MALE AND AGED BETWEEN 17 AND 19"
PRINT #2, " "

FOR i = 1 TO mrecord
   GET 1, i, ss
   IF LEFT$(ss.sex, 1) = "M" AND ss.age >= 17 AND ss.age <= 19 THEN
        PRINT #2, USING " \         \   ##  !  \      \"; ss.sname; ss.age; ss.sex; ss.tel
   END IF
NEXT i

CLOSE 1
CLOSE 2
END

[Download Program]

Exercise : we input the name of a student, (or part of the name), and ask the computer to print out those records that match the name (or part of the name).

Ans :


DEFLNG I-N
DEFDBL A-H, O-Z

TYPE strecord
    sname AS STRING * 30
    age AS INTEGER
    sex AS STRING * 1
    tel AS STRING * 10
    activeflag AS INTEGER
END TYPE

DIM ss AS strecord

OPEN "c:\test\q9_mas" FOR RANDOM AS #1 LEN = LEN(ss)

CLS 0
mrecord = LOF(1) / LEN(ss)
PRINT "Number of records = "; mrecord


L20:
       INPUT "Name to search "; dummy$
       IF dummy$ = "" THEN
          CLOSE
          END
       END IF
       dumb$ = UCASE$(dummy$)
    
       FOR i = 1 TO mrecord
 
          GET 1, i, ss
          duma$ = UCASE$(ss.sname)

          IF INSTR(duma$, dumb$) <> 0 THEN
              PRINT
              PRINT USING "Name      : \         \"; ss.sname
              PRINT USING "Age       : ##"; ss.age
              PRINT USING "Sex       : !"; ss.sex
              PRINT USING "Tel.      : \         \"; ss.tel
              PRINT
          END IF
 
       NEXT i
       PRINT
       GOTO L20

[Download Program]

Up to now, we haven't introduced many Qbasic features. But the features introduced would enable us to do many, many things, limited only by our imagination.

My thinking is that : it is wrong to teach people how to use packages, e.g. (Microsoft's database package in Office 2000), because that would take lot of time, and they only learn the "interface". But if we teach them programming, in a very short time, they are able to write packages. Though their own-brew packages may not be as sophisticated as the commercial ones, their reliability may be better.

It is utterly wrong to think that people would not learn programming, and hence we design user-friendly interfaces for them. But they have to learn one interface for one package, and there are many packages of various designs! Have they learnt programming, e.g. Qbasic (with stripped down features, forsaking many features of history), they can create many programs and they would be more happy.


[Previous][Home][Next]