|
QB入门教程(二) |
|
| 来自: | 作者:Float Pointer |
| 第一节其实还少说了点东西, 因为我太困忘了写. :) --- 自定义数据类型: 象C语言的struct结构,QB也能用TYPE命令自己创造数据类型。如: TYPE student '定义一个“学生”类型 sname AS STRING*8 'NAME是保留字不能用 age AS INTEGER score as integer END TYPE 在TYPE定义里不能有不定长字符串,只能用定长字符串。 TYPE的作用正是处理数据库!看上面这段定义象不象数据库的字段名? 如何打开和处理库文件我们以后再说。 定义完怎样使用呢?用DIM定义变量,用 变量名.字段名 引用: DIM stu as student stu.sname="小芳" 下面看一些例子: 例 2-1 --- ==================================== DEFINT A-Z TYPE score sname AS STRING * 8 chinese AS SINGLE math AS SINGLE english AS SINGLE END TYPE DIM a(10) AS score i = 0 DO 'DO循环开始 INPUT "姓名"; a(i).sname INPUT "分数:", a(i).chinese, a(i).math, a(i).english i = i + 1 LOOP UNTIL LTRIM$(a(i - 1).sname) = "" '>LTRIM$函数是去掉字符串的前(LEFT)空格,因为sname是定长字符串,输入空 '>字符串也有8个空格. LOOP UNTIL表示循环直到后面表达式的值为"真". FOR j = i - 2 TO 0 STEP -1 'FOR循环从I-2到0,"步长"每次减一. PRINT j; ":"; a(j).sname, a(j).chinese, a(j).math, a(j).english NEXT --- ==================================== 按F5运行后先输入姓名,再输入分数,三个分数用逗号分割,必须写 三个数或输入空的逗号,否则会出错继续让你重新输入. 当不输入名字直接回车则停止,但还要输入两个逗号.最后按反序在屏幕上输出. 你会发现第一个INPUT自动加问号而第二个没有,因为第一个INPUT后跟一个分号, 而第二个后跟逗号. ※再看PRINT命令,PRINT命令也可用问号代替.在变量J和";",a(j).sname间 用分号连接,打印出来的内容就是紧挨着的,而后面用逗号连接, QB自动按制表位置放置,每隔八个字符才打印一组数字. 而在每个PRINT命令行的最后,如果没有任何符号就会自动换行, 你甚至可以用一个空的PRINT表示多换一行。如果后面有分号或逗号, 那会影响到下一个PRINT命令的位置。 --- ☆ 表达式 QB的数学运算符有: 加+,减- ,乘* ,除 /,整除 \(截断小数部分), 取模 MOD, 乘方^. 比如上次我们那个画图的程序,循环由0到639,可颜色数只有16种(0-15) 因此我们用MOD运算.所谓取模就是求余数. "怎么没有开方呀?" 有啊, X^.5 不就是对X开方么?(X的0.5次方) 怎样取倒数取平方也知道了吧,不过乘方的速度很慢,二次方最好用 X*X,取倒数最好用 1/x。 此外还有函数,跟数学上的函数概念差不多,比如在立即窗里输入: ? SIN(30) 哎?怎么不对呀?哦,原来用的是弧度,应该是 ? sin(3.141592653589793*30/180) 'PI我背过50位呢。 ;) 运算优先级跟数学一样,括号优先,先函数,再乘方,先乘除, 然后MOD,再加减 QB里很重要的一种运算是逻辑运算。 1.关系运算: = 等于,当在赋值表达式里“=”表示赋值,但在表达 式里代表判断是否等于,等于则为真(-1),否则为假(0) > 大于 < 小于 >= 大于等于 <= 小于等于 <> 不等于 关系运算可以比较数字或字符串。 字符串以ASCII值比较大小。 还记得上一篇所说的QB没有逻辑类型么? 试试 ? 1=3 有什么结果. 你可以 bool=1=2 结果bool得-1, 而bool可以是int,long甚至double类型 2.逻辑运算符 在QB里,逻辑运算符实际上是对变量逐位进行二进制运算的,有逻 辑运算和逻辑判断双重的作用。 逻辑操作符在数学上称做"布尔运算符"(boolean operator) QB的HELP 里有关于它们的“真值表” NOT 取非 AND 与 OR 或 XOR 异或 EQV 等价(同或) IMP 蕴涵 前三个我就不说了,顾名思义么。 如果c=a XOR b,则当a=b时c得0,不相等为1 如果c=a EQV b,则..........1,........0 ....... IMP ......a=1,b=0时c=0,否则c=1 如果A,B每个二进制位都是0或1,即A和B都为真(-1)或假(0), 那它的值必然也是-1(真)或0(假). 如果不为0或-1这两个数 则要用二进制一位一位的算(所有逻辑运算都是这样) 比如 4(100) xor 5(101) =1(001) (括号里是二进制) QB没有逻辑类型,我们通常用这个方法定真假: CONST False=0 CONST True=NOT false '不假可不就是真么。 ;) 只有关系运算才返回的肯定是0或-1,其他逻辑运算除了值是0或-1,否则 一般都不是返回0、-1,而是按位运算的. 下面这是个把十进制数字转换成二进制数字的程序: 例 2-2 --- ==================================== DEFINT A-Z INPUT a FOR i = 15 TO 0 STEP -1 'INT是16位整数,二进制高位在前,因此倒序循环16 次 IF a AND 2 ^ i THEN '2的i次方就是二进制数第i位等于1的情况 PRINT "1"; ELSE PRINT "0"; END IF NEXT '下一次循环 PRINT '多换一行,否则下次运行时不好看,不信你把这行去掉试试。 --- ==================================== 上面用了分行的IF命令,格式是 IF 表达式 THEN 当为真(非0)时许多许多命令 ELSE 当为假(等于0)时许多许多命令 END IF 也就是说IF a AND 2 ^ i THEN...和IF NOT((a AND 2 ^ i)=0) THEN 是等价的。 我们可以反复嵌套,比如 IF .... THEN IF ... THEN IF.... ...... END IF END IF END IF 注意IF和END IF必须配对,否则会报错,因此最好象我这样用缩进格式。 包括循环语句也是,循环也可嵌套,为保证配对也最好用缩进格式。 Q> 这些都是你自已想出来的还是书上说的,你给 Q> 记住了.要是我自已想,哪想的出来啊. :((( Q> 这是不是就叫算法?我现在也没完全看明白. Q> 这可怎么学呀,一个一个的背?不是办法吧? :((( A>当然是我自己编的了.我的教程里没有完全抄袭的程序,最多抄抄公式 A>和算法. :) A>可以说这就是算法吧,编程需要较好的数学能力.比如从10进制转成二进制 A>的公式是用那个数反复除以2,把余数倒过来写,但这种方法只适用于手工计算. A>二进制的特点是第0位表示0或1,第1位表示0或2,第三位表示0或4...第N位 A>表示0或2的N次方. A>2^i正是代表要查的位,比如2^3=8,二进制是1000,AND是位运算,只有两边都是1 A>结果才也是1,比如二进制 10100 and 1000 =0 说明第三位是0, A>如果11010 AND 1000 = 1000 不等于0 说明第三位是1. 在这里提一个系统函数:COMMAND$,没有任何参数。 它是命令行参数字符串。假如把上面这个程序的INPUT A换成 a=VAL(COMMAND$),VAL函数是把字符串转换成数字。 然后编译成EXE文件,假如叫做bin.exe,运行时打: bin 2334 (回车) 你就能看到结果了,好象DOS命令一样,COOL吧。 :) 当然,不编译成EXE也可以看到效果的,在RUN菜单有一项可以修改COMMAND$ 的值。 字符串运算只有加法,就是简单的把两个字符串连接在一起。 但QB的字符串函数非常丰富.比如下面这些常用函数: 下面都用实例来描述,直接在立即窗里输入就能看到效果. VAL: s$="3.1e-2": ? VAL(s$) 把S$字符串转换成数字变量.输出结果: .032 STR$: ?STR$(23) 把数字转换成字符串.是VAL的反函数. CHR$ ?chr$(7) 把数字转成相应的ASCII字符. ASC() ?asc("a") 把字符转成ASCII码,是CHR$的反函数 LEN LEN("12345") 返回字符长度。其实这个LEN可以返回任何变量的长度,包括自定义的TYPE。 在数据库读写中非常有用。 INSTR ?INSTR(1,"Ms Qbasic","basic") 搜索字符串,第一个数字是起始位置,可以省略。 如果返回0则是没找到。 UCASE$ ?UCASE$("DdFd") 全改大写字母 LCASE$全改小写 LTRIM$去前导空格,RTRIM$去后面的空格。前面在例 2-1里已经说过。 HEX$是把十进制数转换成16进制字符串,比如 ?HEX$(255) 显示 FF OCT$是................8 .......... BIN$...没有这个函数啦,要你自己来编才成. ;) 发现了么?凡是反回字符串的函数总有个$,返回数字的就没有. 以后我们还能自己编函数和命令呢. -3- 有了上面那些枯燥无味的基础,这一章我们就可以讨论点具体的了。 下面这个程序是个秒表,按任意键结束。 例 2-3 --- ==================================== t1 = TIMER CLS '清屏 COLOR 14, 1 '设置字符色为14(黄色),背景是1(兰色) WHILE (INKEY$ = "") LOCATE 10, 20 '把光标移到 第10行,第20个字符的位置 t2 = TIMER IF t2 < t1 THEN t1 = t1 - 24 * 60 * 60 PRINT t2 - t1 WEND --- ============ TIMER函数是从午夜零点到现在的秒数,用来计时。 好象只要把当前时间与开始时间相减就成了,可是假如计时中 到了零点(咱们网友的习惯)怎么办? IF语句判断是否过0点,如果过了就把开始时间减去一整天的时间(秒)。 这里的IF语句用的是单行IF命令。格式是: IF 表达式 THEN 为真时命令 ELSE 为假时命令 其中的命令可以用冒号分隔使用多个命令。 INKEY$函数是我最喜欢的输入命令,它运行时读键盘缓冲区,如果没有字符 则返回空( "" 或者CHR$(0) ),有则返回字符. 如果是字母/数字返回的是ASCII码(可以查QB的HELP的CONTANTS有ASCII表) 需要知道的是,ESC是ASCII 27,BACKSPACE是8,ENTER是13,TAB是9, 如果PRINT CHR$(7)就会"滴"的一声响. 如果是控制键(比如光标键,PAGEUP等),返回的是两个字符长的字符串. 第一个是空(CHR$(0) ),第二个是IBM键盘扩展ASCII码,在HELP的 CONTANTS部分有KEYBOARD SCAN CODE表,键盘扫描码基本跟扩展ASC码一样. 比如你想判断输入的字符是否是 键: IF INKEY$=CHR$(0)+CHR$(72) THEN... 很遗憾的是键盘扫描码不等于扩展ASCII码,QB里也没有,我的书里有. 如果你不知道可以编个程序一个一个实验各个键的码. 可以看出,INKEY$执行时不等待直接返回的这种性质可以编出象绘图, 动画控制,游戏等即时控制程序,非常有用. 关于LOCATE命令的格式是 LOCATE 行,列,光标是否可见,光标大小起始行,光标大小结束行 后面的都可以省略,尤其光标大小,很多显示卡都不支持。 而COLOR命令本还有一个参数是设置边框色,但QB有BUG,其实也不支持。 具体颜色代码请读者自己编个程序查查看,用两个FOR循环就成了 范围0-15 Q> t1 = t1 - 24 * 60 * 60 Q> 还有这句,我凭自已想很难想出来这么写. Q> 是不是只能凭经验了? A>当然不是,要经过你的思考.如何把生活中的事物表达成函数式也是一种能力. A>就好象你把物理的应用问题转换成数学方程一样. A>上面这个数是这样算出来的: A>一天24小时,乘以一小时60分钟,乘以一分钟60秒. :) A>有空给你看一个"万年历"的程序,非常著名.它的难点是把格里历转换 A>成公式,用BASIC居然一行就能完成了. A>我以前编过一个叫BT(BatTool)的小软件, 里面就附带这个万年历程序. 下面就介绍一个比较实用的程序 - 破除SHAREWARE时间限制。 以前ZHANG TING前辈介绍过用QBASIC绕过CCDOS97时间限制的 方法。 实现的方法很多,下面是其中一种,可能与ZT的有点不同: 例2-4 --- ===========SAVEDATE.BAS ============ PRINT "DATE "; PRINT DATE$ PRINT "DEL UPDATE.BAT" DATE$="06-01-1997" '假设初次安装日期是97年6月1日 SYSTEM --- ============CC.BAT================== QBASIC /RUN SAVEDATE.BAS > UPDATE.BAT CCDOS rem 这里放输入法, 比如TWABC UPDATE --- ==================================== 实际运行时运行CC.BAT就成了 BTW:此程序我未试过,我支持国产正版软件,至今仍用东方快车版。 :) 我想运行完应该给一个Batch file missing或者“批处理文件丢失” 的错误信息,但无关紧要。 上面这个例子介绍了DATE$函数和DATE$命令(名字都一样),类似的 还有TIME$函数和命令。 DATE$是个"违反常规"的函数,既可以取出日期,也可赋值修改日期. DATE$="日期" 在QB的HELP里规定为"语句"而不是函数, 返回DATE$则规定为"日期函数". TIME$函数你自己试试就知道了. SYSTEM命令如果你用QBASIC或QB启动再OPEN程序运行,就跟END命令一样, 如果你在启动时用 QB /RUN XXX.BAS启动会自动运行BAS程序而不进入编辑界面. 而此时SYSTEM则能自动退出而不返回QB的编辑界面. 也就是说用上面的方法你用不着把程序编译成EXE也能执行,这也是 老式BASIC的运行方式. 上面那个程序如果编译成.EXE文件速度会快一些, 而且屏幕不会闪一下. DOS命令QBASIC虽然只有QB的部分功能,但也能做不少事。 比如我的BWTE的前身就是用QBASIC+批处理的办法。 --- 现在复习一下分支语句。 QB的分支语句有IF,ON... GOTO和SELECT三种,最简单的IF语句是 IF 表达式 THEN 行号 行号有两种,一种是数字,比如 x=1:y=1 IF x=y then 20 END 20 ?20 但这个数字的大小是没有意义的,跟GWBASIC不同。 QB推荐使用字母行标号,与其他语言一样,比如 x=1:y=1 IF x=y then GOTO Label END Label: ? 20 不过GOTO命令最好不要单独使用,结构化编程不使用GOTO 连上面那样的转向语句最好也不用,直接用分行IF...END IF最好。 既然GOTO不好,ON...GOTO也就不说啦. :) 现在只有SELECT没有讲过了.看下面这个例子,可以实现菜单操作: 例2-5 --- ================ ?"========================" ?" 0,E.什么都不干" ?" 1.列目录" ?" 2.改名" ?" 3,4,5.删除" ?"========================" DO A$=INPUT$(1) '从键盘读一个字符. 所谓"读"对于计算机来说就是输入 啦. SELECT CASE A$ CASE "0","E" END CASE "1" SHELL "DIR /P" CASE "2" NAME "C:\AUTOEXEC.BAT" AS "A.BAK" CASE "3" TO "5" KILL "C:\COMMAND.COM" CASE IS > "Z" ?"输了个小写字母?" CASE ELSE ?"输入错误" END SELECT LOOP '没有任何条件参数的DO...LOOP循环是死循环. --- ================ SELECT命令的条件除了可以用取值列表、取值范围外,还可以用IS变量, IS代表初始条件值,就是A$啦。 INPUT$函数需要一个整数的参数,表示输入几个字符. 它直接读指定个数字的符,而且不在屏幕上显示. END命令是结束命令,但可以省略,这样程序就由第一行运行到最后一行. 类似SYSTEM命令, 但不会自动退出. SHELL命令是调用DOS命令. 如果没有参数就可以进入DOS方式,但QB程序 仍然在内存里,比如你在立即窗里输入SHELL,然后打MEM/C/P看看内存还剩多少. 返回是用DOS命令EXIT.如果有参数,当运行完参数里的程序后将会自动 返回. NAME...AS命令相当于DOS命令REN,不过你可不要真的把AUTOEXEC.BAT给改没了. ;) KILL命令相当于DOS命令DEL. 哦,对了,仔细看看这个程序再运行, 可不要运行完了就启动不了计算机了. ;) --- 最后,再总结一下QB的输入命令: INPUT命令,想想分号和逗号的区别。如果INPUT后跟很多变量, 必须用逗号分隔每个变量。而且如果输入的是字符串,不能有逗号。 所以如果输入一行东西不如使用LINE INPUT。比如: LINE INPUT A$ 你可以输入任何字符,直到输入回车为止。当然CTRL-C和CTRL-BREAK不成。 a$=INPUT$(n) 函数是从键盘缓冲区里直接读n个字符,送到a$里, 如果A$=INPUT$(1)就相当于PRESS ANY KEY TO CONTINUE...了。 ( Which key is "ANY KEY"? ;) ) INKEY$函数每次都不等待直接从键盘缓冲区里读一个键,而且可以是 光标控制键。如果用户没有按键直接返回空字符。 无论是哪一种输入方法,QB都可能有汉字不能输入,比如“金”, 这是QB的BUG,如果你用的是MSBASIC 7就能解决问题了。 上面这些囫囵吞枣的灌给大家,恐怕记不住多少,应该 把所有例子都运行一遍,有点印象就好,编的时候再查书。 下次我就讲最吸引人的图形&动画. :) |
|