达内培训:用户界面-屏幕和键盘(二)
#include<stdio.h>
main() { int fc,bc,c; scanf(概嗤先眚\"%d %d\",&fc,&bc); printf(\"Foreground=%d,Background=%d,Color=%d\\n\", fc,bc,fc+bc*16); return(0); } 你可能会同意这样一点,即在大多数情况下,在整个程序中都由程序员明确地写出要送到屏幕上的字节是不现实的。最好是编写一个把文本写到屏幕上的函数,然后频繁地调用这个函数。让我们来分析一下如何构造这样一个函数。 首先,你需要问一下自己:“我需要向这个通用打印函数传递一些什么信息?”作为初学者,你可以传递以下这些信息: ·要写到屏幕上的文本; ·文本的位置(两个坐标值) ·字符的前景色和背景色(两个值) 现在,你知道了需要把什么数据传递给该函数,因此你可以按以下方式来说明这个函数: void PrintAt(char*Text,int x,int y,int bc,intfc) 下一步你需要计算要打印的文本的颜色字节值: int Color=fc+be*16: 然后需要计算文本指针的起始位置: char far*Addr=&screen[(x+y*80)*2]; 需要特别注意的是,为了把文本写到正确的位置上,你必须把偏移量乘以2。此外,使用该语句的前提是在程序中已经定义了变量Screen。如果该变量还未定义,你只需在程序中相应的位置插入下述语句: char far*Screen=MK_FP(0xb800,0x0000); 现在,准备工作都完成了,你可以真正开始向屏幕上写文本了。以下是完成这项任务的程序段: while(*Text) { *(Addr++)=*(Text++); *(Addr++)=Color; } 在还未写完全部文本之前,这段代码会一直循环下去,并把每个字符和对应的颜色写到屏幕上。 以下这个程序中给出了这个函数完整的代码,并且调用了一次该函数。 #include(dos.h> /*This is needed for the MK—FP function*/ char far*Screen=MK_FP(Oxb800,Ox0000): void PrintAt(char*Text,int x,int y,int bc,int fc) { int Color=fc+bc*16; char far*Addr=&screen[(x+y*80)*2]; while(*Text) { *(Addr++)=*(Text++); *(Addr++)=Color; } } main() { int a: for(a=1;a<16:++a) PrintAt(\"This is a test\",a,a,a+1,a); return(0); } 如果比较一下这个函数和固有的打印函数的执行时间,你会发现这个函数要快得多。如果你在使用其它硬件平台,你可以用这里所提供的思路来为你的计算机和操作系统编写一个类似的快速打印函数。
17.5 怎样防止用户用Ctrl+Break键中止程序的运行? 在缺省情况下,MS—DOS允许用户按Ctrl+Break键来中止程序的运行。在大多数情况下,这是一种很有用的功能,它使用户能从程序不允许退出的地方退出程序,或者从一个运行已经失常的程序中退出。
但是,在某些情况下,这种操作是非常危险的。有些程序一旦被中止,可能就会采取“保护”措施,从而使用户能侵入保密数据区。此外,如果程序在更新磁盘上的数据文件时被中止,很可能就会毁坏数据文件,从而毁掉一些有用的数据。 基于这些原因。在某些程序中,解除Break键的功能是很有必要的。警告:在不能百分之百地肯定这样的代码能起作用之前,不要轻易把它加到你的程序中去!否则,一旦这段代码有误并且程序在运行时阻塞住,你就不得不重新启动计算机,而这很可能会毁掉最近对程序所作的修改。 下面介绍如何使Break键失效。这是一种特殊的操作,在有些计算机上无法实现,而有些计算机上根本就没有Break键。因此,c语言中没有一条特殊命令用来解除Break键的功能,而且,即使在以MS:DOS为操作系统的计算机上,也没有一种标准的方法来实现这一点。在大多数计算机上,你必须用一条特殊的机器语言命令来实现这一点。下面是一个在MS-DOS中解除Break键功能的函数: #include<dos.h> void StopBreak() { union REGS in,out; in.x.ax=0x3301: in.x.dx=O: int86(0x21,&in,&out); } 这个函数要设置一组寄存器,即把3301H赋给ax寄存器,把O赋给dx寄存器。然后,它将通过这些寄存器调用中断21H,从而调用DOS,并通知它不再希望让Break键中止程序的运行。 下面是一个用来测试该函数的程序: #include<stdio.h> #include<dos.h> void StopBreak() { union REGS in,out: in.x.ax=Ox3301: in.x.dx=O: int86(Ox21,&in,&out): } int main() { int a: long b: StopBreak(); for(a=O;a<100;++a) { StopBreak(); printf(\"Line %d.\\n\",a); for(b=O;b<500000L;++b); } return O: }
17.6 怎样才能只得到一种特定类型的数据,例如字符型数据? 与几乎所有有关计算机科学的问题一样,这个问题的答案也依赖于你要做什么。例如,如果你要从键盘上读入字符,你可以使用scanf(): scanf(\"%C\",&c); 此外,你也可以使用一些现成的C库函数: c=getchar(); 这些方法所产生的结果基本上都一样,只不过使用scanf()能为程序员提供更多的安全性检查。 如果要接收其它类型的数据,有两种方法可供使用。你可以逐个字符地读入数据,并且每次都检查读入的数据是否正确。你也可以使用scanf(),并通过检查其返回值来确定读入的数据是否都正确。 你可以用第二种方法简单而高效地读入一串记录,并检查它们是否都正确。下例就实现了这一点: #include<stdio.h> main() { int i,a,b: char c; void ProcessRecord(int,int,char); for(i=O;i<i100;++a)/*Read 100 records*/ { if(scanf(\"%d%d%c\",&a,&b,&c)!=3) printf(\"data line %d is in error.\\n\"); else ProcessRecord(a,b,c); } return(O); }