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後接的是條件式的結果,其格式有三種:
|
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
|
|
|
|
|
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與前者代表相同意義
|
|
|
循序檔:檔案內的記錄依序存入,取出亦須依序取出 |
|
|
隨機檔:檔案內記錄依指定的記錄編號,直接存取檔案內的記錄內容 |
|
|
二進位檔:檔案內的記錄乃是以位元組為讀取對象 |
|
檔案內容組成由程式設計者自行設定,用以存放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 |
|
|