1.概說

起源
  乃是於1960年美國Dartmouth學院,J.G. Kemeny與T.E. Kurtz教授所創『Beginer's All-purpose Symbolic Instruction Code』的縮寫(初學者全功能符號化指令碼),目的在幫助初學者很快學習程式設計
軟體來源
 
Gwbasic:附於MSDOS 5.0以前各版本中
Qbasic:附於MSDOS 5.0以後各版本中
Quick Basic:為具有編譯為可執行檔功能的商業軟體
其他各版本的Basic軟體,可以由網路上找到
程式架構
 
早期Gwbasic乃是以行號作為程式執行的順序,為直譯式程式語言。例如

10 A=10:B=20 
20 C=A+B 
30 PRINT C 
RUN
而Qbasic與Quick Basic則引進模組化觀念,利用Subprogram作為程式執行的依據,以程式指令碼順序執行程式。例如:
A=10:B=20
C=ADDAB(A,B)
PRINT C

FUNCTION ADDAB(A,B)
  ADDAB=A+B
END FUNCTION
執行方式
 
在Gwbasic中 輸入run指令
在Qbasic中 選擇ALT+R/START,或是SHIFT+F5便可執行
在Quick Basic中 同Qbasic
新版
  近年來兩位教授也開發新版本的Basic,稱為True Basic。其實也還有其他不同版本的Basic(例如:Power Basic),有興趣可以參考一下

2.資料型態與運算
資料分類
 
依所處理的資料型態:分為數值資料,字串資料
依資料是否具有變動性:分為常數,變數
但是這兩種型態分類是可以組合的,例如數值常數,或是字串變數
資料型態
 
分為字串,整數(整數,長整數),實數(單精準數,倍精準數),紀錄等
各資料特徵則如下列表:
資料型態
佔用記憶體數
型別字元
型別宣告敘述
範例
字串 依字元數決定,最多為32767bytes
$
DEFSTR
str.A$="ATM"
整數 2bytes
%
DEFINT
int.B%=5
長整數 4bytes
&
DENLNG
lng.C&=40000
單精準數 4bytes(1+8+23) 7digital 
!
DEFSNG
sng.D!=1.23E+15
倍精準數 8bytes(1+11+52) 15digital
#
DEFDBL
dbl.E#=1.234D+115
紀錄 依據紀錄類的資料類而定    
[編註:Microsoft對各種資料型別在記憶體存放的方式]
如資料利用16進位制或是8進位制表示時,所需加註的型別符號:
8進位制 &或是&O &25,&O47
16進位制 &H &AD
摘錄一個程式把2進位轉換為16進位的方法:

FUNCTION Bin2Hex$ (Bin$)
    Buf$ = Bin$
    DO
        Temp = 0
        FOR j = 0 TO 7
            Check$ = RIGHT$(Buf$, 1)
            Buf$ = LEFT$(Buf$, LEN(Buf$) - 1)
            IF Check$ = "1" THEN Temp = Temp + 2 ^ j
            IF LEN(Buf$) = 0 THEN
                H$ = HEX$(Temp) + H$
                Bin2Hex$ = H$
                EXIT FUNCTION
            END IF
        NEXT
        H$ = HEX$(Temp) + H$
    LOOP
END FUNCTION

你可以看出這支程式處理的方式嗎?

常數與變數
 
程式語言中為便於運作,依據資料的特性,將記憶體空間劃分不同的區段,並且為該記憶空間指定一符號為代表。例如記憶體中的某個區段空間,該區段存放倍精準數的資料,則該空間為8bytes的記憶體空間
未經宣告的變數乃是以單精準數為內定資料型態
常數乃是將事先定義的值,給定代表某記憶空間的符號。在程式執行過程中,該記憶空間的值保持固定不變,表示該符號的內容不會變動
變數乃是指在程式執行過程中,程式會隨時將計算所得資料,指定給該記憶體空間存放,亦是代表該記憶體空間的符號值內容會一併改變。
變數命名規則
變數只能識別前40字元

第一字元必須使用英文字,不可使用數字

第二字元以後可以使用英文,數字,小數點
保留字不可作為變數名稱
第41字元為型別符號位置
 
例如:
CONST pi=3.14159
DIM saleprice AS (INTEGER,LONG,SINGLE,DOUBLE)
age%=20,my.name$="Tony"
DEF(INT,LNG,SNG,DBL,STR) A,D-F,S
  但是Basic對於變數命名的規則彈性極大(也就是不嚴謹),亦即在單一程式中,以同樣的變數名稱但宣告為不同的資料型別時,視為不同的變數。表示這樣的變數型態,可以同時存在。如此的命名規則,將會導致使用者觀念的混淆。例如:
A%,A! 一般不建議如此命名。如果你的程式中必須以兩種不同資料型態處理資料,建議個別以適當的名稱命名,如下
A.int%,A.lng! 改以不同名稱,如此代表個別不同的資料型別。以此為例:以整數與單精數處理資料,則個別變數的名稱均不同,避免資料處理時的混淆
運算式與運算子
 
運算式
 
A=10:B=20
PRINT C=A+B
注意等號代表指定運算,表示將等號右邊的資料值,或是運算結果指定(傳遞)給等號左邊的變數。運算式包含有算數運算式,關係運算式與邏輯運算式等三種
運算子
  包括:算術運算子,關係運算子,邏輯運算子,函數運算子,字串運算子等。亦稱運算碼
  各種運算子的優先順序與功能如下表所示:
優先
運算子
功能
範例
1
( )
改變運算優先順序 (5+6)/2
2
函數
預先設定的運算 SQR(4)
3
^
指數運算 2^3
4
-
負數運算 -2
5

*

/

乘法運算

除法運算

2*3

2/3

6
\
整數除法運算,求商(資料須先四捨五入) 3\2
7
MOD
餘數運算,求餘數(資料須先四捨五入) 3 MOD 2
8

+

-

加法,減法運算 2+3,3-2
9

=

<>

>

<

<=

>=

關係運算

X=Y

X<>Y...

10
NOT
邏輯補數運算 NOT A
11
AND
且運算 A AND B
12
OR
或運算 A OR B
13
XOR
互斥運算 A XOR B
14
EQV
等效運算 A EQV B
15
IMP
隱含運算 A IMP B
[範例試題]

3.輸入與輸出
常用敘述
 
REM 程式註解,或是利用’表示。例如:' this is a remark of this program:a=b+3
CLS ( 0 | 1 | 2 ) 清除螢幕
SLEEP n 讓程式暫停 n 秒
SWAP 交換兩變數內容,通常用在資料結構部分
輸入敘述
 
INPUT "prompt" (;|,),var1,var2,...  
LINE INPUT 專門輸入字串資料,字串長度限制254字元
READ... DATA  
RESTORE  

INPUT a$, b$, c$
READ id%, Name$, salary! 
Print a$; id%, b$; Name$,c$;salary! 
RESTORE female 
READ id%, Name$, salary! 
Print a$; id%,b$; Name$,c$;salary! 
Data 7, "James Bound", 2.4E+10 
female: 
Data 8, "Mary Wu",2.3D+5
            
  • 這支程式,主要利用input敘述,讓使用者輸入三個資料,並依序放在三個變數中,不論所輸入的資料特性為何,均變為文字資料
  • 利用read...data在程式中讀取內建的資料項
  • 利用restore跳到指定的標籤讀取資料,倘若restore後並未接任何標籤,則是由第一個data讀取資料
   

input "Please Input your Name:",yourname$
print
line input "Your address:",youradd$
print
          
 
輸出敘述
 
PRINT 一般常用輸出的指令,輸出資料間無區隔符號。輸出數值資料前後會加上空白,如果數值為負值,則會在前方加上負號;字串資料則直接顯示字串內容;後續接","表示資料在特定輸出區輸出,如果接";"表示連續輸出
WRITE 用法類似PRINT敘述,每一資料間以","區隔。輸出數值資料前後不加空白;字串資料會自動加上雙引號,例如"TEST"
LPRINT 由印表機輸出,其輸出格式同print指令
格式化輸出
 
TAB(n) 水平定位顯示,在第 n 欄 column 開始輸出資料,類似以絕對位置輸出
SPC(n) 由目前游標算起空出 n 個空格,在第n+1欄開始輸出資料,類似以相對位置輸出
SPACE$(n) 輸出空白字元
連續顯示
分區域顯示
組合多行敘述為一行敘述
游標定位指令
LOCATE 移動游標到指定位置,與控制游標大小(與螢幕解析度有關) LOCATE [row],[column]
CSRLIN 取得目前游標所在列Row位置 row%=csrlin
POS 取得目前游標所在欄Column位置 col%=pos(0)
PRINT USING 以特定格式顯示資料
字串資料
印出字串資料的第一個字元
印出字串資料的全部字元
\n個空白\
  • 印出字串資料的前n+2個字元
  • 若n+2大於字串資料長度,則右邊以空白補足
數值資料
未使用格式設定
  數值前後均有空格,前空格顯示符號,後空格作為間格用
使用格式設定
  • 代表一個數字欄位,負號佔用一個位數
  • 數值比格式少,則向右對齊;比格式多,則全部印出,左邊並加上%
  • 小數點後的每一個#代表一位
  • 數值小數位比格式少,則補0;數值小數比格式多,則四捨五入
  • 格式符號代表顯示一位
  • 在格式字串左:於左側顯示正、負符號
  • 在格式字串右:於右側顯示正、負符號
  • 若數值資料為負,則在右邊顯示負號
  • 此符號只能放在格式字串的右邊,如放在左側則會產生錯誤
  • 格式符號不代表顯示一位
  • 由個位數起往左顯示千位符號
  • 格式符號可以出現在格式字串中任一位置
**
  • 格式符號代表顯示二位
  • 列印的數值資料前有空白位置,便自動印滿*符號
  • 單一*符號視為一般字元,只有兩個**符號才是格式字串
$$
  • 格式符號代表顯示兩位
  • 資料左邊顯示$
**$
  • 具備**與$$的功能
  • 在數值資料左邊顯示$,前頭空白位置補上*(如果有負號,則先顯示,即**-$),為一般支票金額常用的數值格式
^^^^
  • 用來印出數值的浮點數部分E+nn。共有四個位元:第一個位元印出E,第二個位元印出指數的正負值,其餘兩個欄位印出指數值(固定為兩位)

4.程式流程控制

IF..THEN..ELSE(決策判斷)


cls
input "請輸入一數值",mynumber%
if (mynumber% mod 2) then
  print "你輸入了奇數";
end if
print mynumber%
  • 此一程式中,如果使用者輸入一偶數,被2除後,所得值為0。在basic中視為假,則if判斷式不成立,程式直接執行end if後的敘述。
  • 如果輸入奇數,所得值為1,在basic中視為真,則判斷式成立,執行if敘述內的指令,則訊息便顯示。而離開if敘述後程式繼續執行,印出輸入數值與2整數除後的答案
   

cls
input "請輸入一數值",mynumber%
if (mynumber% mod 2) then
  print "你輸入了奇數"
else
  print "你輸入了偶數"
end if
print mynumber%
  • 在此段程式中,則利用了else指令。當if判斷式不成立時,程式便直接進入else後段的程序執行。
  • 利用這種特色,可以建立所謂的巢狀判斷。利用不同的判斷式,依序建立判斷條件,逐層過濾程式

SELECT..CASE(決策判斷)

  在以上的範例中,雖然提到巢狀的判斷式,但是如果判斷的條件過多,對於程式的維護也會顯得相當吃力。所以便可以利用SELEST..CASE的判斷式


cls
input "你的成績",score%
select case score%
case 100
  print "Best"
case is >90
  print "Good"
case 60 to 89
  print "so so"
case is <60
  print "bad"
end select
  • 本程式輸入一數值,然後利用select 判斷式進行判斷。如果找到第一個符合的條件式後,便執行該條件式後的第一個敘述。該敘述執行完後,便跳到end select後繼續執行後續的程式
  • select case 後接條件式
  • case後接的是條件式的結果,其格式有三種:
      特定值
     

    範圍值 to 範圍值

      is 關係式

FOR..NEXT(定迴圈,預知迴圈執行次數)

  屬於先判斷後執行,指令的格式:

  FOR 計數指標 =起始值 TO 終止值 STEP 遞增值
  • 遞增值內定為1,且可為正值或負值
  • 當計數指標=終止值,迴圈結束
  • 若起始值大於終止值,迴圈結束
  • 迴圈執行次數為:(終止值-起始值)/遞增值+1

for x=1 to 9
  for y=1 to 9
    print x;"*";y;"=";x*y
  next y
next x
          
  • 本程式乃是一99乘法表
  • 利用迴圈代表重複執行的次數
  • 迴圈計數器的增值未標記時,表示每一迴圈增加1
   

s=0
for x=1 to 5
  s=x+s
  x=x+1
next
print s
  • 本程式目的在顯示迴圈計數器的變化
  • 首先x=1,經第一次迴圈計算s=1,x=2
  • 因為剛才迴圈計數器x已經變為2,所以第二次進入迴圈時x便由2成為3,此時s=4,而x=4
  • 進入第三次迴圈時,x由4變為5,此時s=9,而x=6
  • 進入第四次迴圈時x=6已經大於迴圈的上限值,所以迴圈結束

DO..LOOP(不定迴圈,無法預知迴圈執行次數)


cls
input "輸入累加目標值(a%):";a%
s=0:x=0
do while x<=a%
  s=s+x
  x=x+1
loop
print s
  • 本範例屬於前置式迴圈
  • 使用者輸入一固定值,程式先設定兩個變數,變數s作為累加計算,變數x作為與變數a相比較值,測試迴圈結束的條件是否滿足
  • 本迴圈進入前先比較測試條件是否滿足,如果滿足測試條件,則迴圈繼續執行;如果測試條件不滿足,則離開迴圈
  • 使用者如果輸入負值,則滿足測試條件x<=a%,迴圈不執行,直接印出結果。即本迴圈至少執行0次
   

cls
input "輸入累加目標值(a%):";a%
s=0:x=0
do 
  s=s+x
  x=x+1
loop while x<=a%
print s
  • 本範例屬於後置式迴圈
  • 使用者輸入一固定值,程式先設定兩個變數,變數s作為累加計算,變數x作為與變數a相比較值,測試迴圈結束的條件是否滿足
  • 本程式先進入迴圈執行,而後比較測試條件是否滿足。如果測試條件滿足,則繼續迴圈執行;否則結束迴圈
  • 本迴圈至少執行1次
   

cls
input "輸入累加目標值(a%):";a%
s=0:x=0
do 
  s=s+x
  x=x+1
  if x>a% then
     exit do
  end if
loop
print s
  • 本範例屬於永久迴圈
  • 結束迴圈的條件判斷式寫在迴圈中,如果滿足該判斷式,則會以exit do離開迴圈
  • 為避免形成無窮迴圈,必須注意加注離開迴圈的條件式。
  • 本迴圈一定執行1次

WHILE..WEND(不定迴圈)


cls
num=65
while num < 91
  print "num=";num;"='";chr$(num);"'"
  num=num+1
wend          
  • 事先給定一變數值num=65
  • 迴圈的測試條件為num<91
  • 在迴圈中連續執行將相對應的數碼以chr$()函數印出該字元,並將num值每一迴圈+1
  • 當num=91時便結束迴圈
   

cls
bincode$=""
input "請輸入轉變值",source
while source <> 0
  remain=source mod 2
  source=source \ 2
  bincode$=str$(remain)+bincode$
wend
print bincode$
  • 本式乃是將使用者輸入的值轉變為2進位值
  • 事先設定最終顯示的變數內容為空字串
  • 利用環圈控制,當所轉換的值變為0才結束環圈
  • 先計算所的的餘數remain
  • 再計算轉換後的商數
  • 將餘數轉變為字串後與逐層加入最終顯示字串

常見範例

  在一些參考書中,常見到一些程式範例。在此便將這些程式範例列舉說明,供讀者參考:


'九九乘法表
FOR x = 1 TO 9
	FOR y = 1 TO 9
	    PRINT x; "*"; y; "="; x * y
    NEXT y
NEXT x
  • 本程式執行結果,將九九乘法表以直列方式,顯示出來
  • 想一想:如何把它變成橫式列印(提示print using)
   

'繪出圖形
 FOR x = 1 TO 9
     FOR y = 1 TO x
         PRINT "*";
     NEXT
     PRINT
 NEXT
  • 重複列印字元圖形
  • 想一想:如何利用函數string$把要列印的字元顯示出來
   

'計算偶數總合
sum = 0
FOR x = 1 TO 1000
    IF not(x MOD 2) THEN
    	sum = sum + x
    END IF
NEXT
PRINT sum
  • 利用迴圈讀取資料,計算該資料是否為偶數。如果該數據為偶數則經過mod運算後必為0,又經過not運算,便會成為1,代表true。IF後的關係式如果為true,便會執行then後的運算式,便進行加總符合條件的數據
  • 想一想:如果計算奇數,該如何處理
   

'計算所輸入值的階層值
INPUT m.x
sum = 1
FOR i = 1 TO m.x
  sum = sum * i
NEXT
PRINT sum
  • 所謂階層值,便是計算數據的連乘積,利用迴圈一直計算到迴圈結束的終止值
   

'計算輸入3個值,比較大小
OPTION BASE 1
PRINT "Input 3 Numbers"
DIM a(3)
FOR x = 1 TO 3
    INPUT a(x)
NEXT
FOR i = 2 TO 1 STEP -1
   FOR j = 1 TO i 
       IF a(j) > a(j + 1) THEN
          tmp = a(i)
          a(i) = a(i + 1)
          a(i + 1) = tmp
       END IF
NEXT j,i
FOR x = 1 TO 3
    IF x = 3 THEN
      PRINT a(x)
    ELSE
      PRINT a(x); "<";
    END IF
NEXT
  • 程式構想:設計一個陣列存放所輸入的值,然後把該陣列排序,排序後在依據排序的結果,把各個陣列值以及其間的關係子顯示出來
  • 為防止陣列觀念誤差,所以宣告陣列的註標由1開始
  • 利用氣泡排序的方法,以陣列中各元素兩兩比較,把值比較大的元素,排到陣列尾端
  • 想一想:如果利用選擇排序法,則程式如何撰寫呢?
   

'成績分級
INPUT "Please Input score ?", score%
SELECT CASE score%
       CASE IS >= 90
           PRINT "Score is "; score%; "degree A"
       CASE IS >= 80
           PRINT "Score is "; score%; "degree B"
       CASE IS >= 70
           PRINT "Score is "; score%; "degree C"
       CASE IS >= 60
           PRINT "Score is "; score%; "degree D"
       CASE ELSE
           PRINT "Score is "; score%; "degree E"
END SELECT
 

5.陣列與紀錄
陣列
  如果資料具有一致性,或是具有相同的型態,便必須利用具有代表性的變數表示,陣列便是一群具有相同資料型態變數的集合
宣告方法
  DIM 陣列名稱 ( 下註標 to 上註標,下註標 to 上註標 ) [AS TYPE]
注意細節
 
陣列的宣告與一般變數宣告方法相同,差在陣列具有註標宣告
陣列內的所有資料型態相同,同時為字串、整數(整數或長整數)、或是實數(單精準數或倍精準數)陣列
陣列註標內定下限值為0,OPTION BASE n (n=0,1)改變內定陣列註標下限值為0或1
未宣告陣列維度,其最高註標為10。一經宣告便不可改變維度,同一程式中,可以具有相同名稱,但是不同資料型別的陣列
若宣告陣列為字串陣列,則陣列內所有資料均為空字串
若宣告陣列為數值陣列,則陣列內所有資料均為0
陣列最高維度為60維,註標值範圍為-32768~+32767
動、靜態陣列
 
所謂靜態陣列乃是在程式編譯時便配置記憶體空間,而在程式執行時才配置記憶體空間者稱為動態陣列
常數宣告陣列註標為靜態陣列;以變數宣告陣列註標為動態陣列
利用假命令設定後續所宣告陣列的特性為:
  靜態陣列:REM $STATIC
  動態陣列:REM $DYNAMIC
靜態陣列經ERASE後,乃是清除其陣列內容;而動態陣列經ERASE後乃是釋放其記憶體空間,必須再經過宣告才可使用該陣列
只有動態陣列才適用重新宣告陣列 REDIM敘述,類似先ERASE陣列,再用DIM宣告陣列。此時只可以改變陣列的註標值,而不可改變陣列的維度以及陣列的資料型態
 
範例

    cls
    dim a%(-2 to 8)
    for i=-2 to 8
      a%(i)=i
    next
          
  • 宣告陣列註標的範圍-2到8,共計11個陣列值,且陣列為整數型態
   

     cls
     dim a(3,3)
     for i=1 to 3
       for j=1 to 3
         a(i,j)=4*i+j
         print using "####;a(i,j)";
     next j,i
          
  • 宣告一二維陣列
  • 利用雙層迴圈設定陣列值並利用格式化輸出方式將陣列內容輸出
   

     rem $dynamic
     cls
     dim a(4,3)
     for i=1 to 4
       for j=1 to 3
         read a(i,j)
     next j,i
     redim a(3,2)
     restore ano
     for i=1 to 4
       for j=1 to 3
         read a(i,j)
     next j,i
     data 1,2,3,4,5,6,7,8,9,10,11,12,13,14
     ano:
     data 10,9,8,7,6,5,4,3,2,1
          
  • rem $dynamic為假命令,宣告後續所有宣告的陣列均為動態陣列
  • 利用第一迴圈設定陣列值
  • 以redim指令將原陣列自記憶體釋放,並重新宣告陣列的二維維度
   

     input "陣列註標:", x
     dim a(x) as integer
     for i = 1 to x
       a(i)=2*i+1
     next
     print
     redim a(x - 2) as integer
     for i = 1 to x - 2
       a(i)=3*i+2
     next
          
  • 利用變數x,代表動態陣列a(x)
  • 以redim改變陣列的註標值,但資料型態不可改變
紀錄
 
由於變數與陣列對資料處理的能力均不夠,故必須利用紀錄型態加強Basic對資料處理的能力。變數處理一個資料,而陣列只能處理一串相同的資料類型。所以如果需要在處理的資料包含多重的類型,便必須利用紀錄
紀錄一般稱為Record或是『使用者定義資料型態』,紀錄內的每一個元素稱為『欄位』(Field)。格式如下:
    TYPE 紀錄名稱
      欄位名稱 as 資料型態
      [欄位名稱 as 資料型態]
      .....
    END TYPE
  • 紀錄名稱為一種資料格式,就像是Basic中的整數,或是實數
  • 欄位名稱為識別紀錄中的一個欄位
  • 資料型態便是該紀錄中的欄位所必須具有的一種Basic內部的資料型態
  • 所以紀錄可以視為Basic中的一種特殊的資料集合,並將這種資料集合一起運用,表示
命名規則
 
紀錄的命名規則與變數相同
欄位命名規則與變數相同,但必須注意:
1 不能使用陣列名稱
2

同一紀錄中的欄位名稱不可相同,而不同紀錄的欄位名稱則可以相同

資料型態必須為Basic中所定義的資料型態

TYPE只是定義紀錄資料型態,在正式使用還必須經過宣告的程序,此一型態才可以使用

 
範例

    TYPE ScoreRec
      rName as string * 8
      rChi  as integer
      rMath as integer
      rAve  as single
    end TYPE

    option base 1
    dim stu(5) as ScoreRec

    for i=1 to 5
      read stu(i).rName
      read stu(i).rChi
      read stu(i).rMath
      stu(i).rAve=(stu(i).rChi+stu(i).rMath)/2
    next
    
    data Mary,70,50
    data John,100,90
    data Peter,80,90
    data Lin,90,60
    data Wu,60,100
  • 利用TYPE宣告一具有自訂型態的資料集合ScoreRec,該集合中具有紀錄姓名,國文成績,數學成績,以及一個計算平均成績的欄位。注意各欄位的資料與欄位型態必須配合
  • 定義一陣列具有前所宣告的資料集合型態,並利用迴圈讀取程式檔案內的內建資料。其中stu(i).rAve為前兩欄位的計算結果
  • 注意這種程式的寫法,可以發揮在撰寫畫面或是讀取一系列的紀錄值。而內定的資料,則可以利用外部資料檔案的格式讀取

6.函數

  所謂函數,乃是該程式語言在設計時,便已預先設計好的運算程序。設計者只需套用該程序,便可直接得到結果

函數一般可以分為:

  • 內儲函數 Built-in Function
  • 自訂函數 User defined Function
內儲函數

數值函數:傳回數值資料

函數名稱
功能
範例
 ABS() 傳回絕對值 ABS(6)=6,ABS(-3)=3
SGN() 傳回符號值 SGN(-50)=-1,SGN(0)=0,SGN(34)=1
FIX() 傳回整數值 FIX(34.253)=34,FIX(-25.13)=-25
INT() 傳回小於或等於的最大值 INT(24.32)=24,INT(-26.78)=-27
CINT() 傳回四捨五入的整數值 CINT(1.49)=1,CINT(-1.59)=-2
SQR() 傳回平方根 SQR(4)=2
SIN() 傳回正弦值  
COS() 傳回餘弦值  
TAN() 傳回正切值  
EXP() 傳回ex 注意此為自然對數,如需改為數學應用式,則為LOG(X)/LOG(10)
LOG() 傳回自然對數值LN(X)
ASC(x$) 傳回x$的第一個字元的ASCII碼 ASC("ABC")=65 第一個字元為A
VAL(x$) 將x$轉為數值 VAL("234")= 234 2的左側有一空白字元
LEN(x$)
LEN(X)
傳回x$或變數X的位元數 LEN("ABC我")=5 字串為5byte
LEN(AB)=2 變數ab為單精準數,佔記憶體2byte
CLEN(x$) 傳回x$的字元數 CLEN("ABC我")=4

字串函數:傳回字串資料

函數名稱
功能
範例
CHR$() 傳回字元碼所代表的字元 CHR$(65)="A"
STR$() 將數值型態資料改為字元型態 STR$(123)=" 123" 數值123轉變為字串" 123"長度為4byte
LCASE$() 字元改為小寫 LCASE$("ABCdef")="abcdef"
UCASE$() 字元改為大寫 UCASE$("ABCdef")="ABCDEF"
SPACE$(n) 傳回n個空白字元 SPACE$(5)
STRING$(n,X$) 重複x$內的第一個字元n次 STRING$(5,"A")="AAAAA"
LEFT$(x$,n) 由字串X$左邊開始取nbyte LEFT$("ABCDEF",3)="ABC"
RIGHT$(x$,n) 由字串X$右邊nbyte位置開始取剩餘byte RIGHT$("ABCDEF",4)="CDEF"
MID$(x$,n,m) 由字串左邊n byte位置開始取m個byte MID$("ABCDEF",3,2)="CD"
CMID$(x$,n,m) 由字串左邊n 字元位置開始取m個字元 MID$("ABC我DEF",3,2)="C我"
LTRIM$(X$) 將X$內的前置空排字元刪除 LTRIM$(" 123")="123"
RTRIM$(X$) 將X$內尾隨的空白字元刪除 RTRIM$("123 ")="123"
DATE$ 取得系統日期 顯示格式:mm-dd-yyyy
TIME$ 取得系統時間 顯示格式:hh:mm:ss
LSET 字串向左對齊,填入變數或欄位中
RSET 將字串向右對齊,填入變數或欄位中
HEX$(x) 傳回代表x(10進位制)的16進位制字串
OCT$(x) 傳回代表x(10進位制)的8進位制字串

亂數函數:傳回亂數值

函數名稱
功能
範例
TIMER 由午夜時刻起到現在的總秒數  
RANDOMIZE 設定亂數種子值

RANDOMIZE 27 (亂數種子最好是質數)

RND 產生介於0<=X<1的亂數值 產生方式
自訂函數

  可以區分為單行式,與多行式的自訂函數

單行式自訂函數

DEF FNSQR(X)=2^X

PRINT FNSQR(2)
	  
  • 單行函數前方一訂要用DEF FN函數名 為函數命名

多行式自訂函數

DEF FNCASE(X)
	SELECT CASE X
		CASE IS >0
		  FNCASE=1
		CASE IS 0
		  FNCASE=0
		CASE <0
		  FNCASE=-1
	END SELECT
END DEF
	  
  • 敘述區段式的自訂函數,必須以END DEF為函數結束
其實你會發現這樣的函數定義方式有一些特殊的地方:
自訂函數名稱必須以fn為開始
當使用多行式函數時,乃是以函數名稱,作為函數運算結果的傳回
當然還可以利用函數式作為自訂函數的一種撰寫模式

7.次常式與程序式

模組與程式
 
Basic程式乃是以BAS副檔名為主,此為單一模組,也就是一個BAS檔就是一個模組。但是如果把系統建立為單一模組,則不易進行程式的維護。所以一般均會依據系統分析時,所規劃的功能,分別撰寫成不同的模組,在編譯的時候,將各模組個別編譯,並一起連結,形成的系統,這便是模組化的設計
例如:教務系統中具有成績、選課、學籍等管理功能,便將個別的管理功能建立為單一模組,最後將三個模組連結成單一系統程式,便成為教務系統了
模組化程式設計時,為便於管理程式,經常將程式區分為若干小段落,各段落負責個別功能。而每一段落間待運算資料的傳遞,以及各段落的功能,均有相關的定義以及標準。這些程式片斷稱為程序Procedure。可簡單區分如下:
使用者自訂函數 DEF FN... END DEF
次常式 GOSUB... RETURN
副程式

SUB... END SUB

FUNCTION...  END FUNCTION

次常式 Subroutine
 
在撰寫程式時,如果單一模組中,經常會進行例行運算的程式段落,便可以獨立出來,變成一個小的程式區段。該程式區段以特殊的標記名稱作為識別,當該區段執行完畢後,程式的執行權便又回到原呼叫點,繼續執行下一敘述

k=1
print "A Subroutine Test"
print "This is the starter k=";k
gosub addk
print "First time return from subroutine k=";k
gosub addk
print "Second time return from subroutine k=";k
end
addk:
  k=k+1
return           
              
  • 利用gosub,將程式移轉到次常式行,而在次常式部分利用return將程式執行權移轉回主程式
  • 在這支程式中,ADDK這個次常式會經常被呼叫,所以便與主程式分開,獨立撰寫
  • 注意呼叫ADDK後,程式所繼續執行的程式點
副程式,程序式 Subprogram
 
以堆積木的概念來看,副程式便是一軟體系統的各部功能獨立的小積木。把一塊塊的積木堆積起來,便是一個完整的成品。但是堆成一個房子的積木模型時,你一定會先把牆壁歸牆壁,屋頂歸屋頂的方式,先把房子各部先拼湊起來,然後再把屋頂與牆壁合併起來。所以各部屋頂或是牆壁便是在軟體程式中的副程式
在此要提出一個軟體IC的概念,當整個系統是利用模組化概念組成時,當系統中某一部份的功能有更新時,便此需將該更新的軟體模組替換,便可達到系統升級的目的。而軟體形成IC概念時,便表示某一部份的軟體模組,可以利用物件的概念構成軟體系統,如此便可加速軟體系統的開發時程,提高軟體的生產力。例:

DECLARE SUB prodnum (x!)
INPUT "Please Input a number:", a
CALL prodnum(a)
'prodnum a

SUB prodnum (x)
        sum = 1
        FOR i = 1 TO x
                sum = sum * i
        NEXT
        PRINT sum
END SUB
              
  • 在這支程式中第一行Declare敘述乃是Qbasic自行加入的宣告 ,主要的功能乃是檢查參數的個數與資料型態是否符合
  • 利用Call敘述呼叫一處理程序,並將待處理資料以傳值方式傳遞給副程式。此處也可以寫成prodnum a,a為實引數
  • 當資料傳遞到副程式後,副程式以虛引數 X 承接進行處理。並將處理結果顯示
  • 副程式Prodsum便可以在任何時候加以應用,使用時只需交所需處理的資料傳遞給該程序便可以得到結果
  • 副程式的呼叫方法
    CALL 副程式名 CALL SUBPROC(X,Y)
    程式名 傳遞參數 SUBPROC X,Y
    變數的生命
     
    早期的Basic語言變數代表全域變數Global Variable,但是在QB中卻具有更深的意義
    變數的可視性
    變數的生命週期
    變數類型
    產生方式
    可視性
    生命週期
    區域變數 任一變數一經宣告,均為區域變數

    僅能在該副程式中存在

    在副程式中利用shared敘述,將區域變數變為全域變數

    暫時性
    全域變數

    在主程式中以

    • 以dim shared,redim shared宣告陣列與一般變數
    • common shared宣告變數

    等方式成為全域變數

    • shared:於個別程序式宣告,使變數在主程式可見
    • dim shared:同一模組的整個程式
    • common shared:多重模組,於每一模組前宣告
    永久性
    靜態變數 宣告後,會記憶該變數內的資料。等程式執行到該程序時,便又可以存取該變數內的資料 存在於該副程式中 永久性
    自動變數 宣告後便以區域變數格式存在 僅能在該副程式中存在 暫時性
    比較以下兩支程式的差異
    
    declare sub test()
    common shared x,y
    cls
    x=x+1:y=y+1
    for i=1 to 5
    	test
    nest
    end
    
    sub test static
    	x=x+1
    	y=y+1
    	print "x=";x,"y=";y
    end
    	  
    • 主模組宣告變數x,y具有全域變數特性
    • 次程式 test 宣告 static 屬性,使副程式中的所有變數均為static變數
       
    
    declare sub test()
    common shared x,y
    cls
    x=x+1:y=y+1
    for i=1 to 5
        test
    next
    end
                
    sub test
    static y
    	x=x+1
            y=y+1
            print "x=";x,"y=";y
    end
              
    • 主模組宣告變數x,y具有全域變數特性
    • 次程式 test 宣告 y 變數為 static 變數,使 y 變數原先全域變數屬性消失
    • 但是變數 x 仍具有全域變數屬性
    由以上程式執行結果,可以發現:static敘述可以設定變數為靜態變數。而且可以蓋過任何在主系統中以dim shared或是common shared宣告為共同變數的相同變數名稱
    但是sub,function敘述中的屬性則不具有此一功能,亦即只能宣告變數具有靜態變性,而無法改變其優先權
    變數的傳遞
     
    QB變數的傳遞方式可以分為:
    傳值呼叫 call by value:實引數與虛引數佔用不同的記憶體空間位址,虛引數資料變動,實引數不會變動。可以保存實引數的內容
    傳址呼叫 call by address:實引數與虛引數佔用相同的記憶體空間,當虛引數內容改變,實引數也隨著改變。實引數的值無法保存

    在QB中,如果實引數為常數、或運算式便為傳值呼叫,其他傳遞方式均為傳址呼叫

    但如果在變數前後加上括號,則變為傳值呼叫。請參考以下範例:

    引數為常數運算式屬於傳值呼叫
    若變數外加()表示以傳值呼叫傳遞引數資料

    call ADD(3)
    call ADD(x+3)
    call ADD((x),(y))
    		
    引數為變數陣列屬於傳址呼叫
    call ADD(x,y)
    		
    如果欲取得變數在記憶體中的偏移位址則可利用VARPTR(變數名稱)取得。實引數與虛引數的名稱即使相同,但實質上仍為佔用不同記憶體位址的變數
    函數式 Function
     
    函數式與副程式作用類似,但是唯一的差別在於Function可以使用在一個運算式中,但是副程式Sub不行。看範例 。函數式Function與自訂函數DEF FN的差別,在於Function具有遞迴呼叫的能力,而Def FN不具有遞迴功能
    
    input "請輸入數值:",num%
    print factorial&( num% )
    
    function factorial&( n% )
    	if n% > 0 then
    		factorial&=n% * factorial&( n% - 1 )
    	else
    		factorial&=1
    	end if
    end function
    	  
    • 上例便是遞迴呼叫的一範例,程式功能在計算數據的階層值
    • 在QB中以遞迴方式最多只能求取12!
    
    input x
    sum=1
    for i=1 to s
    	sum=sum*i
    next
    print sum
    
    • 若以此方式求取階層值,則可以求取34!

    8.檔案處理
    資料檔案概念
     
    檔案是同一類資料的集合體,一般檔案可以分為程式檔與資料檔。此處所討論的檔案以資料檔為主
    資料檔的結構乃是一群相關的記錄所組成,其結構的順序為:位元組Byte、欄位Field、記錄Record、檔案File等。你可以用虛擬的表格方式,來看待檔案中的記錄與欄位。相同一列的稱為記錄,而相同一欄的稱為欄位
    QB依據資料的存取方式,檔案分為三種:循序檔,隨機檔,二進位檔。各種檔案的特性如下段所述
    檔案處理的步驟,一般為:開啟檔案、讀取資料,關閉檔案。檔案在處理時均是透過主記憶體中的緩衝區,進行檔案處理,例如:程式讀取資料時,先到磁碟機中將資料讀進緩衝區,爾後依序在緩衝區中讀取所需資料,若是緩衝區內並無所需資料,便到磁碟機的相對檔案內讀取。同樣當程式寫入資料時,乃是先把資料寫入緩衝區,當緩衝區的容量填滿後,才將緩衝區的資料寫入到磁碟檔中
    存放在檔案內的資料全部都是以字元格式存放!此觀念太重要了。所以才會以不同的字元長度儲存數值資料。並且當資料由檔案讀出進行處理時,必須以函數進行轉換,字元轉為數值,才可進行後續處理
    檔案開啟與關閉
     
    檔案的開啟
    語法1 OPEN 檔案名稱 [FOR 模式1] [ACCESS 存取] [鎖定] AS [#]檔案代碼 [LEN=記錄長度]
    模式1
    存取
    鎖定
    指定存取模式
    OUTPUT 循序輸出
    INPUT 循序輸入
    APPEND 循序增添
    RANDOM 隨機存取
    BINARY 二進位存取
    設定檔案的操作方式
    READ 唯讀
    WRITE 輸出
    READ WRITE 讀寫
     
     
    在Multiprocessing環境下,限定其他
    processing存取所開啟的檔案
    SHARED 共享
    LOCK READ 唯讀鎖定
    LOCK WRITE 寫入鎖定
    LOCK READ WRITE 讀寫鎖定
    語法2 OPEN 模式2 ,[#]檔案代碼,檔案名稱[,記錄長度]
    模式2
    指定存取模式
    O
    循序輸出
    I
    循序輸入
    A
    循序增添
    R
    隨機存取
    B
    二進位存取
    語法1與語法2之不同在於:語法2不提供任何網路存取與檔案共享的特性,但與早期BASIC程式具有相容性
    開啟循序檔範例
    模式1 open "test.dat" for output as #1
    模式2 open "o",#1,"test.dat"
    開啟隨機檔範例(內定開啟檔案模式)
    模式1 open "test.dat" for random as #1 len=25

    模式1

    open "test.dat" for random as #1 len=25
    field #1,8 as name$,6 as age%,11 as address$

    模式2 open "r",#1,"test.dat" len=25
      以open指令開啟檔案,但未指定所開啟檔案的型態內定為開啟隨機檔
    檔案的關閉
    語法: CLOSE [[#]檔案代碼][,[#]檔案代碼...]
    必須注意的是:程式內雖把變數資料寫入緩衝區,還必須將檔案關閉,資料才會正確寫入資料檔內。而所使用的檔案代碼以及所佔用的緩衝區的記憶體空間才會釋放,該緩衝區代碼才可以供給其他檔案的應用
    未指定檔案代碼時表示將所有已開啟的檔案均關閉
    與檔案有關的函數
    EOF End of File函數
    LOC 上一次存取資料的檔案指標位址。如:loc(n)
    LOF Length of File函數。如:lof(1)
    SEEK

    檔案指標pointer敘述與函數,設定或傳回下一次存取資料的檔案指標位置。seek(n)表示搜尋在編號n的記憶體檔案緩衝區內,可供存放資料的起始位置。seek #1與前者代表相同意義

    循序檔:檔案內的記錄依序存入,取出亦須依序取出
    相關敘述與函數
    OPEN 開啟檔案
    CLOSE 未指定檔案代碼時表示關閉所有檔案,並且結束檔案代碼與檔案間的關係
    若程式結束,但未以此指令正確關閉檔案。則所輸入的資料,並不會寫入檔案而會隨程式結束而流失
    PRINT #
    WRITE #
    PRINT # USING
    資料輸出到檔案
     
     
    INPUT #
    LINE INPUT#
    INPUT$
    CINPUT$
    讀取欄位資料對應到相對應的變數
    由檔案中讀取一個記錄給對應的變數
    從指定檔案中讀取字元資料。例如:input (1,#1),input$()
    與INPUT$類似,但中文字與英文字元視為相同的一次讀取對象
    因為有記錄分隔字元,所以每筆記錄的長度不須一致
    因為記錄長度不固定,所以比較節省磁碟的儲存空間
    作業時必須依序存取記錄,所以存取速度慢,效率較差

    修改檔案內部資料費時,且須佔用較大的主記憶體空間

    儲存數值資料時,以定點格式(數值不超過單精數的有效位數7位或是倍精數的16位)或是浮點格式(超過數值的有效位數者)儲存
    紀錄間以使用CRASC(13)+LFASC(10)作為記錄的分隔字元
    以PRINT輸出資料,若資料後加","表示紀錄加註CR+LF;若資料後加";"表示紀錄不加註CR+LF
    若以WRITE輸出資料,則以逗號""作為欄位的分隔字元,且字元資料前後加雙引號
    open "test.dat" for output as #1
    print #1,string$(50,65)
    a%=lof(1)
    close
    
    • 結果a%=52
    • 因為以print輸出資料,而string$函數後並未加上”;”,表示必須附帶輸出CR+LF
    • 若STRING$後有加上”;”,表示資料必須連續輸出,便沒有CR+LF。此時a%=50
    open "test.dat" for output as #1
    write #1,string$(50,65)
    b%=lof(1)
    close
    
    • 結果b%=54
    • 因為以write輸出資料,在資料檔內會以雙引號" "加在字串左右,且加註CR+LF
    • 以write顯示資料,STRING$後若沒有其他資料輸出,則不可加上”;”
    看循序檔範例
    隨機檔:檔案內記錄依指定的記錄編號,直接存取檔案內的記錄內容
     
    相關敘述與函數
    FIELD 設定檔案內資料的欄位寬度
    PUT # 寫入資料。put #1, [,記錄代號[,變數]]
    GET #
    INPUT$
    CINPUT$
    讀取資料
    讀取資料函數
     
    LSET
    RSET
    字串資料左對齊,以便存入檔案
    字串資料右對齊

    MKD$

    MKI$

    MKL$

    MKS$

    Mask Double,將倍精數數值資料轉換為8個位元的字串資料
    Mask Integer,將整數數值資料轉換為2個位元的字串資料
    Mask Long,將長整數數值資料轉換為4個位元的字串資料
    Mask Single,將單精數數值資料轉換為4個位元的字串資料
    CVI
    CVS
    CVL
    CVD
    Convert Integer,將2個位元的字串資料轉換為整數數值資料
    Convert Single,將4個位元的字串資料轉換為單精數數值資料
    Convert Long,將4個位元的字串資料轉換為長整數數值資料
    Convert Double,將8個位元的字串資料轉換為倍精數數值資料

    每一筆記錄與欄位間,不須加上分隔字元,檔內全部都是資料

    因為沒有分隔字元,所以每筆記錄及欄位長度均需固定一致

    由於紀錄長度固定,所以比較浪費磁碟的儲存空間
    作業時只要指定記錄編號,即可存取,所以存取速度快,效率較佳
    修改資料省時,而且佔用的記憶體空間較小
    隨機檔內不使用任何字元作為記錄區隔,檔案內存放的均是資料,所以記錄長度為一致
    隨機檔內存放數值的方式,與該數值宣告時所佔用的記憶體空間數一致。例如整數型態數值,宣告時佔有記憶體空間2byte,存放在資料檔內亦相同佔有2byte資料檔長度
    看隨機檔範例
    二進位檔:檔案內的記錄乃是以位元組為讀取對象
     
    檔案內容組成由程式設計者自行設定,用以存放ASCII及非ASCII字元的檔案,例如特定資料格式的檔案,或是依據系統讀取資料所需,而特別設計資料存放格式的檔案均屬之
    開啟時必須以BINARY格式開啟,並視檔案內的資料為連續的位元組;而以RANDOM格式開啟的檔案,則把檔案內的資料視為一連續的紀錄必須了解該檔案的編碼格式,才能對該檔案進一步處理
    看二進位檔範例
    檔案與目錄維護
     
    在QB中提供與DOS命令類似的敘述,處理程式對檔案以及目錄處理的功能。如下表:
    敘述
    功能
    語法
    範例
    CHDIR 改變目前所在目錄 CHDIR 路徑名稱 CHDIR "C:\DOS"
    MKDIR 產生新的目錄 MKDIR路徑名稱 MKDIR "CHI"
    RMDIR 刪除已存在的目錄 RMDIR 路徑名稱 RMDIR "CHI"
    FILES 列示檔案清單 FILES [檔案名稱] FILES "*.BAS"
    KILL 刪除檔案 KILL 檔案名稱 KILL "*.TMP"
    NAME 更改檔案名稱 NAME 舊檔名 AS 新檔名 NAME "CH1.TMP" AS "CH1.DAT"
    SHELL 暫時離開BASIC,回到DOS系統 SHELL [命令字串] SHELL