这听起来有些混乱(Escape键后面跟着换码符),但这也正是这些字符之所以被叫做换码符的原因。Escape键用来通知字符的接收者下一个字符是换码符,而不是普通的字符。换码符本身可以是任何字符,甚至可以是另一个Escape键。具体用什么字符来代表所要求的命令,由读入这些字符并等待相应命令的程序来决定。
这方面的一个例子是ANSI.SYS设备驱动程序,该程序由CONFIG.SYS文件装入,它会拦截所有送往屏幕的字符,并按换码序列的要求处理这些字符。ANSI.SYS的作用是提供一种方法来打印彩色的、带下划线的或闪烁的文本,或者执行象清屏这样的高级命令。ANSI.SYS的优点在于你不必知道你使用的是哪种显示器或显示卡,因为ANSI.SYS会替你处理这个问题。你只需在要送往屏幕的字符串中的合适位置加入换码符,ANSI.SYS会替你处理其余的事情。例如,如果你输入了“\033H4Hello there,”ANSI.SYS就会在屏幕上打印出红色的“Hello there”——它将发现Escape键(\033),读入命令(在这里是H4,即以红色打印其余的字符),然后打印其余的字符("Hello there")。
在ANSI.SYS之前,换码符被用在老式的集中化计算机环境(一个主机连接着很多哑终端)中。在那个时代,终端自身没有计算能力,不能显示图形,而且大部分都是单色的,不能显示彩色。但是,每台显示器都有一套由主机发送给显示器的换码符,用来指示显示器做清屏、加下划线或闪烁这样一些事情。与使用ANSI.SYS一样,只要程序员在发送给显示器的字符串中加入换码符,显示器就会执行相应的命令。
今天,这种类型的换码序列已经不再使用了。然而,当时还有许多其它类型的被定义为换码符的字符序列,它们一直被延用至今,并且仍然在被广泛使用。例如,在介绍如何把一个八进制值或十六进制值赋给一个变量的问题中,笔者就使用了一种换码符(在十六进制中使用“Ox”,在八进制中使用“\”)。注意,这些字符并没有用Escape键来作特殊标识,但它们的确被用来表示其后的字符有某种特殊性。实际上,反斜杠(\)经常被当作一个换码符来使用。例如,在c语言中,你可以用“\n”来通知计算机“执行一次换行操作”,或者用“\t”来执行前进一个tab符的操作,等等。 如何编写C语言程序判断一个字符是否是字母或数字
怎样判断一个字符是否是一个字母?
字母表中的所有字母(包括计算机键盘上的所有键)都被赋予了一个值,这些字符及其相应的值一起组成了ASCII字符集,该字符集在北美、欧洲和许多讲英语的国家中得到了广泛的使用。字母字符被分成大写和小写两组,并按数字顺序排列。有了这种安排,就能很方便地检查一个字符是否是一个字母以及是大写还是小写。下面这段代码说明了如何检查一个字符是否是一个字母:
int ch ;
ch=getche() ;
if((ch>=97) && (ch<=122))
printf(" %c is a lowercase letter\n" ,ch);
else if ((ch>=65) && (ch<=90))
print(" %c is an uppercase letter\n" ,ch);
else
printf(" %c is not an alphabet letter\n" ,ch) ;
在上例中,变量ch的值与十进制值进行比较。当然,它也可以与字符本身进行比较,因为ASCII字符既是按字符顺序定义的,也是按数字顺序定义的。请看下例:
int ch ;
ch=getche() ;
if((ch>='a') && (ch<='z'))
printf("%c is a lowercase letter\n" ,ch);
else if ((ch>='A') && (ch<='Z'))
print(" %c is a uppercase letter\n" ,ch);
else
printf(" %c is not an alphabet letter\n" ,ch);
你可以随便选择一种方法在程序中使用。但是,后一种方法的可读性要好一些,因为你很难记住ASCII码表中每个字符所对应的十进制值。
怎样判断一个字符是否是一个数字?
在ASCII码表中,数字字符所对应的十进制值在48到57这个范围之内,因此,你可以用如下所示的代码来检查一个字符是否是一个数字:int ch ;
ch=getche() ;
if((ch>=48) && (ch<=57))
printf(" %c is a number character between 0 and 9\n" ,ch) ;
else
printf(" %c is not a number\n" ,ch) ;
与20.18相似,变量ch也可以和数字本身进行比较:
int ch ;
ch=getche () ;
if((ch>='O') && (ch<='9'))
printf(" %c is a number character between 0 and 9\n" ,oh) ;
else
printf(" %c is not a number~n" ,ch) ;
同样,选用哪一种方法由你决定,但后一种方法可读性更强。 C语言按科学记数法打印数字的方法 为了按科学记数法打印数字,必须在printf()函数中使用"%e"格式说明符,例如:
float f=123456.78;
printf("%e is in scientific\n",(float)i);
当然,如果要对整数进行这样的处理,则必须先把它转换为浮点数:
int i=10000;
printf("%e is in scientific\n",f);
下面的程序演示了格式说明符“%e”的作用:
#inclued <stdio. h>
main ( )
{
double f = 1.0 / 1000000. O;
int i ;
for(i = O; i< 14; ++ i )
{
printf( " %f = %e\n" , f , f );
f *= 10.0;
}
return( 0 );
} C语言打印出美元一美分值的方法 C语言并没有提供打印美元一美分值的现成功能。然而,这并不是一个难题,编写一个输出货币值的函数是非常容易的。当你编写了一个这样的函数后,你就可以在任何需要它的程序中调用它了。
这样的函数往往既短小又简单,下文中将简单地描述它的工作方式。在本书中,这个函数被分解成几个较小的容易编写的程序段,因而很容易理解。把一个程序分解为较小的程序段的原因在第11章中已经介绍过了。
这个函数需要使用一些标准C函数,因此你需要包含一些相应的头文件。在任何使用这个函数的程序的开头,你都应该确保包含以下这些头文件:
#tinclude <stdio. h>
#include <stdlib. h>
# include <math. h>
# include <string. h>
包含了所需的头文件后,你就可以创建一个接受美元值并按带逗号的形式打印该值的函数:
void PrintDollars( double Dollars )
{
char buf[20];
int l , a;
sprintf( buf, " %olf", Dollars );
l = strchr( buf, '.') - buf;
for(a= (Dollars<0.0); a<1; ++a)
printf( "%c", buf[a]) ;
if(( ( ( l - a ) % 3) == 1 )&&(a !=l - 1 ) )
printf( " ," ) ;
}
你可能习惯于用浮点数来表示实数,这是很平常的。然而,浮点数通常不适合于金融工作,因为它有较大程度的不准确性,例如舍入错误。双精度类型的准确度比浮点数高得多,因此它更适合于真正的数字工作。
只要写一个把整数值传递给该函数的程序,你就可以很方便地测试该函数。然而,该函数还不能打印小数或“零头”,为此,还要专门编写一个完成这项工作的函数:
void PrintCents ( double Cents)
{
char buf[10 ];
sprintf( buf, "%-. 02f" , Cents );
printf("%s\n" , bur + 1 + (Cents <= 0) );
上述函数接受一个小数值并按正确的格式打印该值。同样,只要编写一个把小数值传递给该函数的程序,你就可以测试该函数了。
现在你已经有了两个函数:一个能打印货币值的美元部分(整数部分),另一个能打印货币值的美分部分(小数部分)。你当然不希望先把一个数分解成两部分,然后再分别调用这两个函数!但是,你可以编写一个函数,用它来接受货币值并把该值分解成美元和美分两部分,然后再调用已有的另外两个函数。这个函数如下所示:
void DollarsAndCents ( double Amount )
{
double Dollars = Amount >= 0.0 ? floor( Amount ) : ceil(Amount) ;
double Cents = Amount - (double) Dollars;
if ( Dollars < 0.0 ) printf( "-" );
printf( " $" );
PrintDollars ( Dollars ) ;
PrintCents ( Cents ) ;
}
这就是所要的函数! DollarsAndCents()函数接受一个实数值(double类型),并按美元一美分的格式把该值打印到屏幕上。如果你要测试一下这个函数,你可以编写一个main()函数,让它去打印多个美元一美分值。下面就是这样的一个函数:
int main()
{
double num= . 0123456789;
int a ;
for(a = 0; a<12; ++a )
{
DollarsAndCents( num );
num *= 10.0;
}
return( 0 );
}
它的输出结果为:
$O.01
$O.12
$1.23
$12.35
$123.46
$1,234.57
$12,345.68
$123,456.79
$1,234,567.89
$12,345,678.90
$123,456,789.OO
$1,234,567,890.OO
如果你想按其它的形式打印货币值,你可以很方便地修改这个程序,使其按其它格式打印数字。 怎样用0补齐一个数字? 要想用0补齐一个数字,可以在格式说明符中的“%”后面插入一个以0开始的数字。可以用具体的例子来清楚地解释这一点:
/*Print a five-character integer,padded with zeros.*/
printf("%05d",i);
/ * Print a floating point, padded left of the zero out to
seven characters. * /
printf("% 07f", f);
如果你没有在数字前面加上O这个前缀,那么数字将被用空格而不是O来补齐。
下面的程序演示了这种技巧:
#include <stdio. h>
int main ()
{
int i = 123;
printf( "%d\n", i ) ;
printf( " %05d\n", i );
printf( "%07d\n", i );
return( 0 );
}
它的输出结果为:
123
00123
OO00123 怎样防止用户向一个内存区域中输人过多的字符? 有两个原因要防止用户向一个内存区域中输入过多的字符:第一,你可能只希望处理固定数目的字符;第二,可能也是更重要的原因,如果用户输入的字符数超过了缓冲区的容量,就会溢出缓冲区并且破坏相邻的内存数据。这种潜在的危险在C指南书籍中常常会被忽略。例如,对于下面的这段代码,如果用户输入的字符超过了50个,那将是很危险的:
char bufE50];
scanf("%s",buf);
解决这个问题的办法是在scanf()中指定要读入的字符串的最大长度,即在“%”和“s”之间插入一个数字,例如:
"%50s"
这样,scanf()将最多从用户那里接受50个字符,任何多余的字符都将保留在输入缓冲区中,并且可以被其它的scanf()所获取。
还有一点需要注意,即字符串需要有一个NUL终止符。因此,如果要从用户那里接受50个字符,那么字符串的长度必须是51,即50个字符供真正的字符串数据使用,还有一个字节供NUL终止符使用。
下面的程序测试了这种方法:
# include <stdio. h>
/*
Program to show how to stop the
user from typing too many characters in
a field.
*/
int main()
{
char str[50]; /* This is larger than you really need * /
/*
Now, accept only TEN characters from the user. You can test
this by typing more than ten characters here and seeing
what is printed.
*/
scanf( "%10s", str);
/*
Print the string, verifying that it is, at most, ten characters.
*/
printf( "The output is : %s. \n", str) ;
return (0) ;
下面是这个程序的一个运行例子。当输入supercalifragilisticexpialidocious后,程序将输出supercalif. 为什么有时不应该用scanf()来接收数据? 尽管在读取键盘输入时,scanf()是用得最多的函数,但有时最好还是不使用scanf()。这些情况可以分为以下几类:
必须立刻处理用户所击的键
如果你的程序要求一旦某键被按下,就要立刻做出反应,那么scanf()就没有用了。scanf()至少要等到Enter键被按下后才会做出反应,而你根本不知道用户什么时候才会按下Enter键——也许是一秒钟以后,也许是一分钟以后,也许是一个世纪以后。
尽管在实时程序中,例如在计算机游戏中,用scanf()来读取键盘输入是很糟糕的,然而在通用的实用程序中,这同样也是很糟糕的。例如,在操作一个由字母组成的菜单时,用户肯定喜欢只按a键,而不是按完a键后再按一下Enter键。
遗憾的是,标准C函数库中并没有能立刻响应用户击键的函数,因此你只能依靠辅助函数库或编译程序所带的一些特殊函数。
当scanf()对输人进行分析时,你所需要的数据可能会被忽略掉
scanf()是一个很精明的函数——有时精明得过分了。为了满足用户对输入数据的要求,scanf()会跳行,会丢掉不合适的数据,并且会忽略空白符。
然而,有时你并不希望scanf()精明到这种程度!有时你想把用户所键入的内容全部看作是输入,不管它是太多还是太少。一个不适合使用scanf()的例子就是要从用户那里接受文本态命令的程序一一事先你并不知道用户要键入的句子中会有多少个单词。在这种情况下,就不能使用scanf(),因为你不知道用户什么时候才会按下Enter键。
预先不知道用户会输人哪种类型的数据
有时,你已经准备好要接受用户的输入,但你不知道用户将输入一个数字,还是一个词,或者是某个特殊的字符。在这种情况下,你必须按某种中性格式,例如字符串,来接受用户的输入,并且在继续下一步操作之前判断输入的数据是哪一种类型。
此外,scanf()还会带来这样一个问题,即它会把不合适的输入保存在输入缓冲区中。例如,如果你期望读入一个数字,而用户却输入了一个字符串,那么有关的代码可能会无限循环下去,因为它试图把这个字符串当作一个数字来分析。下面这个程序演示了这一点:
#include<stdio.h>
main()
{
int i;
while(scanf("%d",&j)==O)
{
print{("Still looping.\n");
}
return(O);
}
如果你象程序所期望的那样输入了一个数字,那么这个程序完全能正常运行。但是,如果你输入了一个字符串,那么这个程序就会无限循环下去。 C语言向屏幕上写数据的最简单和最快的方法是什么?
向屏幕上写数据的最简单的方法是什么?
C语言包含了大约几百个向屏幕上写数据的函数,很难决定在某一时刻最适合用哪一个函数来向屏幕上写数据。许多程序员只是简单地选择一个或两个打印函数,并且以后只使用这些函数。这是一种可以接受的编程风格,尽管这样的程序员也许不是总能写出最好的代码。一个程序员应该做的就是把每个打印函数的设计目的和最佳用法都回顾一遍,这样,当他需要向屏幕上打印数据时,他就能选出最佳的函数,甚至还可以自己编写一些打印函数。
要成为一个真正熟练的程序员,第一步要做的工作的一部分就是学会正确地使用标准C语言库中的打印函数。让我们仔细地分析一下其中的几个函数。
printf(<format string>,variables);
printf()是使用最广泛的打印函数。在把文本输出到屏幕上时,有些程序员只使用这个函数。尽管如此,该函数的设计目的只是用来把带格式的文本打印到屏幕上。实际上,“printf"是“print formatted(带格式打印)”的缩写。带格式的文本是指文本中不仅仅包含写到代码中的字符串,还包含由程序动态生成的数字、字符和其它数据;此外,它的内容可以按一种特定的方式显示,例如,它可以按所指定的小数点前后的位数来显示实数。正是由于这个原因,所以printf()函数是不可缺少的!
那么,为什么有时又不使用printf()呢?这里有几个原因。
第一个原因是程序员想更清楚地表达他的意图。程序员可能只对printf()函数提供的诸多功能中的一小部分感兴趣,在这种情况下,他可能想使用只提供这一小部分功能的那个函数,例如:
putchar(char);
该函数的作用是把一个字符送到屏幕上。如果你只需做这部分工作,那么它是十分合适的。除此之外,它就不见得有什么好处了。然而,通过使用这个函数,你就能非常清楚地表达相应的那部分代码的意图,即把单个字符送到屏幕上。
puts(char*);
该函数的作用是把一个字符串写到屏幕上。它不能象printf()一样接受额外的数据,也不能对传递过来的字符串加以处理。同样,通过使用这个函数,你就能非常清楚地表达相应的那部分代码的意图。
程序员不使用printf()的第二个原因是为了提高程序的执行效率。printf()函数的额外开销太多,也就是说,即使是进行一次简单的操作,它也需要做大量的工作。它需要检查传递过来的字符串与格式说明符是否匹配,还需要检查传递过来的参数个数,等等。上面提到过的另外两个函数没有这些额外的开销,因此它们可以执行得非常快。这个因素对大多数向屏幕上写数据的程序来说并不重要,但是,在处理磁盘文件中的大量数据时,它就显得很重要了。
不使用printf()的第三个原因是程序员想减小可执行程序的大小。当你在程序中使用了标准C函数时,它们必须被“连接进来”,也就是说,它们必须被包含进所生成的可执行文件中。对于象putchar()和puts()这样简单的打印函数,对应的程序段是很短的,而对应于printf()的程序段却相当长——特别是因为它必然要包含前两个函数。
第二个原因可能是最不重要的一个原因,然而,如果你在使用静态连接程序,并且想保持较小的可执行文件的话,那么这就是一项重要的技巧了。例如,尽可能减小TSR和其它一些程序的大小是很值得的。
无论如何,程序员都应根据自己的目的来选择需要使用的函数。
向屏幕上写文本的最快的方法是什么?
通常,你不会过分关心程序写屏幕的速度。但是,在有些应用中,需要尽可能快地写屏幕,这样的程序可能包括:- 文本编辑器。如果不能很快地写屏幕,则由用户输入文本所造成的屏幕滚动和其它有关操作可能会显得太慢。
- 活动的文本。在同一区域快速地打印字符,是获得动画效果的一种常用手段,如果不能快速地把文本打印到屏幕上,那么动画就太慢了,视觉效果就不会好。
- 监视器程序。这样的程序要连续地监视系统、其它程序或硬件设备,它可能需要每秒在屏幕上打印多次状态的更新信息,而通过标准c库函数实现的屏幕打印对这样的程序来说很可能显得太慢。
那么,在这些情况下应该怎么办呢?有三种办法可以加快程序写屏幕的速度:选用额外开销较小的打印函数;使用提供了快速打印功能的软件包或函数库;跳过操作系统,直接写屏幕。下面将按从简到繁的顺序分析这几种办法。
1、选用额外开销较小的打印函数
有些打印函数的额外开销比别的打印函数要多。“额外开销”是指与其它函数相比,某个函数必须做的额外工作。例如,printf()的额外开销就比puts()多。那么,为什么会这样呢?
puts()函数是很简单的,它接受一个字符串并把它写到显示器屏幕上。当然,printf()函数也能做同样的工作,但它还要做大量其它的工作——它要分析送给它的字符串,以找出指示如何打印内部数据的那部分特殊代码。
也许你的程序中没有特殊字符,而且你也没有传递任何这样的字符,但不幸的是,printf()无法知道这一点,它每次都必须检查字符串中是否有特殊字符。
函数putch()和puts()之间也有一点微小的差别——在只打印单个字符时,putch()的效果更好(额外开销更少)。
遗憾的是,与真正把字符写到屏幕上所带来的额外开销相比,这些C函数本身的额外开销是微不足道的。因此,除了在一些特殊情况下之外,这种办法对程序员不会有太大的帮助。
2、使用提供了快速打印功能的软件包或函数库
这可能是有效地提高写屏速度的最简单的办法。你可以得到这样的一个软件包,它或者会用更快的版本替换编译程序中固有的打印函数,或者会提供一些更快的打印函数。
这种办法使程序员的工作变得十分轻松,因为他几乎不需要改动自己的程序,并且可以使用别人花了大量时间优化好了的代码。这种办法的缺点是这些代码可能属于另一个程序员,在你的程序中使用它们的费用可能是昂贵的。此外,你可能无法把你的程序移植到另一种平台上,因为那种平台上可能没有相应的软件包。
不管怎样,对程序员来说,这是一种既实用又有效的办法。
3、跳过操作系统,直接写屏幕
由于多种原因,这种办法有时不太令人满意。事实上,这种办法在有些计算机和操作系统上根本无法实现。此外,这种办法的具体实现通常会因计算机的不同而不同,甚至在同一台计算机上还会因编译程序的不同而不同。
不管怎样,为了提高视频输出速度,直接写屏是非常必要的。对全屏幕文本来说,你可能可以每秒种写几百屏。如果你需要这样的性能(可能是为了视频游戏),采用这种办法是值得的。
因为每种计算机和操作系统对这个问题的处理方法是不同的,所以要写出适用于所有操作系统的程序是不现实的。下文将介绍如何用Borland c在MS-DOS下实现这种办法。即使你不使用这些系统,你也应该能从下文中了解到正确的方法,这样你就可以在你的计算机和操作系统上写出类似的程序了。
首先,你需要某种能把数据写到屏幕上的方法。你可以创建一个指向视频缓冲区的指针。在MS-DOS下使用Borland C时,可以用下述语句实现这一点:
char far*Sereen=MK_FP(0xb800,Ox0000);
far指针所指向的地址并不局限于程序的数据段中,它可以指向内存中的任何地方。MK_FP()产生一个指向指定位置的far指针。有些其它的编译程序和计算机并不要求区分指针的类型,或者没有类似的函数,你应该在编译程序手册中查找相应的信息。
现在,你有了一个“指向”屏幕左上角的指针。只要你向该指针所指向的内存位置写入若干字节,相应的字符就会从屏幕的左上角开始显示。下面这个程序就是这样做的:
#include<dos.h>
main()
{
int a:
char far*Screen=MK_FP(Oxb800。Ox0000):
for(a=0;a<26;++a)
sereen[a*2]='a'+a:
return(O);
}
该程序运行后,屏幕顶端就会打印出小写的字母表。
你将会发现,字符在视频缓冲区中并不是连续存放的,而是每隔一个字节存放一个。这是为什么呢?这是因为一个字符虽然仅占一个字节,但紧接着它的下一个字节要用来存放该字符的颜色值。因此,屏幕上显示的每个字符在计算机内存中都占两个字节:一个字节存放字符本身,另一个字节存放它的颜色值。
这说明了两点:首先,必须把字符写入内存中相隔的字节中,否则你将会只看到相隔的字符,并且带有古怪的颜色。其次,如果要写带颜色的文本,或者改变某个位置原有的颜色,你就需要自己去写相应的颜色字节。如果不这样做,文本仍然会按原来的颜色显示。每个描述颜色的字节既要描述字符的颜色(即前景色),又要描述字符的背景色。一共有16种前景色和16种背景色,分别用颜色字节的低4位和高4位来表示。
这部分内容对一些缺乏经验的程序员来说可能有点复杂,但还是比较容易理解的。只要记住有16种颜色,其编号范围是从。到15,要得到颜色字节的值,只需把前景色的值和背景色值的16倍相加即可。下面这个程序就是这样做的:
#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);
}
如果比较一下这个函数和固有的打印函数的执行时间,你会发现这个函数要快得多。如果你在使用其它硬件平台,你可以用这里所提供的思路来为你的计算机和操作系统编写一个类似的快速打印函数。
C语言编程中,怎样在屏幕上定位光标? C标准并没有提供在屏幕上定位光标的方法,其原因很多。C被设计成能在各种各样的计算机上工作,而其中的许多机型都有不同的屏幕类型。例如,在行式打印终端上,不能向上移动光标;一个嵌入式系统甚至也可能是用c编写的,而在它的应用场合可能根本就没有屏幕。
尽管这样,在屏幕上定位光标对你的程序来说还是有用的。你可能希望给用户一个吸引人的视觉效果,并且只能通过移动光标来实现;你还可能想用相应的输出命令尝试一点动画效果。尽管这方面没有标准的处理方法,但还是有好几种方法可以解决这个问题。
首先,编译程序的开发者会提供一个函数库,专门处理基于他们的编译程序的屏幕输出操作,其中肯定会有定位光标的函数。但是,很多人认为这是最差的解决办法,因为每一个开发商都可以自由地开发自己的实现方法,所以在一种编译程序上开发的程序,当移到另一种编译程序上时,几乎必然要重写,更别说移到另一种计算机上了。
其次,可以定义一套标准的库函数,并使编译程序的开发者在他的编译程序中实现这套函数。流行的Curses软件包就起源于这种思路。在大多数计算机和编译程序中都可以使用Curses,因此,用Curses实现屏幕输出的程序在大多数计算机和编译程序中都可以工作。
第三,你可以利用这样一个事实,即你想打印到其上的设备会用一种特定的方式解释你送过去的字符。终端(或屏幕)应设计成按一种标准方式去解释送给它们的字符,这就是ANSI标准。如果你认为你的计算机是遵循ANSI标准的,你就可以通过打印相应的字符来控制屏幕把光标定位在所需的位置上,并且可以把这种操作和其它操作组合在一起。 为什么直到程序结束时才看到屏幕输出? 有时,依赖于所使用的编译程序和操作系统,系统会对输出进行缓冲。“缓冲”是指任何要送到设备上的输出,无论设备是屏幕、磁盘还是打印机,都被存储起来,直到输出量大到足以进行高效的输出。当存储了足够多的输出信息时,再整块地向指定的设备输出。
这种过程会给不了解其作用的程序员带来两个问题。首先,在程序送出输出内容后,它可能要再过一段时间后才会在屏幕上显示出来。如果程序员正在试图跟踪程序的当前运行状态,他就会被这种效果所困扰。
其次,更可怕的是,在程序显示提示信息并等待用户输入时,很可能就会发生问题。当程序试图从用户那里得到输入信息时,输出缓冲区可能还未被“填满”,因此送往屏幕的提示信息可能不会显示出来,用户也就不知道程序已经在等待他进行输入了——他所能得出的结论只能是这个“可爱”的程序突然停止工作了。
如何解决这个问题呢?有两种办法。第一种办法是在程序的开始部分,在进行任何输出之前,加入下述语句:
setvbuf(stdout,NULL,_IONBF,O);
该语句的作用是实现程序到屏幕的无缓冲输出。当这条命令被执行后,每一个被送往屏幕的字符都会立即显示出来。
用这种办法解决这个问题确实比较方便,但是还不够理想。笔者不想在这里对屏幕输入和输出展开一次技术讨论,但笔者要指出这样一点,即对屏幕输出进行缓冲是有充分的理由的,并且你还会希望这样做。
这佯一来,就引出了解决输出缓冲问题的另一种办法。当fflush()命令作用于一个输出缓冲区时,它会使该缓冲区“倒空”自身,而不管它是否已被填满。因此,为了解决屏幕缓冲问题,在需要“倒空”输出缓冲区时,你只需插入如下命令:
fflush(stdout):
在程序要求用户输入之前,或者在程序开始一项耗时的大型的计算工作之前,最好先“倒空”输出缓冲区。这样,当程序暂时停住时,你就能清楚地知道其原因了。 C语言中判断两个字符串是否相同的方法 C语言提供了几个标准库函数,可以比较两个字符串是否相同。以下是用strcmp()函数比较字符串的一个例子:
#include <stdio. h>
#include <string. h>
void main (void);
void main(void)
{
char* str_1 = "abc" ; char * str_2 = "abc" ; char* str_3 = "ABC" ;
if (strcmp(str_1, str_2) == 0)
printf("str_1 is equal to str_2. \n");
else
printf("str_1 is not equal to str_2. \n");
if (strcmp(str_1, str_3) == 0)
printf("str_1 is equal to str_3.\n");
else
printf("str_1 is not equalto str_3.\n");
}
上例的打印输出如下所示:
str_1 is equal to str_2.
str_1 is not equal to str_3.
strcmp()函数有两个参数,即要比较的两个字符串。strcmp()函数对两个字符串进行大小写敏感的(case-sensitiVe)和字典式的(lexicographic)比较,并返回下列值之一:
----------------------------------------------------
返 回 值 意 义
----------------------------------------------------
<0 第一个字符串小于第二个字符串
0 两个字符串相等 ·
>0 第一个字符串大于第二个字符串
----------------------------------------------------
在上例中,当比较str_1(即“abc”)和str_2(即“abc”)时,strcmp()函数的返回值为0。然而,当比较str_1(即"abc")和str_3(即"ABC")时,strcmp()函数返回一个大于0的值,因为按ASCII顺序字符串“ABC”小于“abc”。
strcmp()函数有许多变体,它们的基本功能是相同的,都是比较两个字符串,但其它地方稍有差别。下表列出了C语言提供的与strcmp()函数类似的一些函数:
-----------------------------------------------------------------
函 数 名 作 用
-----------------------------------------------------------------
strcmp() 对两个字符串进行大小写敏感的比较
strcmpi() 对两个字符串进行大小写不敏感的比较
stricmp() 同strcmpi()
strncmp() 对两个字符串的一部分进行大小写敏感的比较
strnicmp() 对两个字符串的一部分进行大小写不敏感的比较
-----------------------------------------------------------------
在前面的例子中,如果用strcmpi()函数代替strcmp()函数,则程序将认为字符串“ABC”等于“abc”。 C语言打印字符串的一部分的方法