19.1 应该在变量名中使用下划线吗?
在变量名中使用下划线是一种风格。使用或完全不使用下划线都没有错误,重要的是要保持一致性——在整个程序中使用相同的命名规则。这就是说,假如你在一个小组环境中编程,你和其它小组成员应该制定一种命名规则。并自始至终使用这种规则。假如有人使用了别的命名规则,那么集成的程序读起来将是很费劲的。此外,你还要与程序中用到的第三方库(假如有的话)所使用的风格保持一致。假如可能的话,你应该尽量使用与第三方库相同的命名规则,这将加强你的程序的可读性和一致性。
许多C程序员发现在命名变量时使用下划线是很方便的,这可能是因为加下划线会大大加强可读性。例如,下面的两个函数名是相似的,但使用下划线的函数名的可读性更强:
check disk space available(selected disk drive);
CheckDiskSpaceAvailable (Selected Disk Drive);
上例中的第二个函数名使用了骆驼式命名法——见19.5中关于骆驼式的解释。
请参见:
19.2 可以用变量名来指示变量的数据类型吗?
19.5 什么是骆驼式命名法?
19.6 较长的变量名会影响程序的速度、大小或效率吗?
19.9 一个变量名应该使用多少个字母?ANSI标准答应有多少个有效字符?
19.10 什么是匈牙利式命名法?应该使用它吗?
19.2 可以用变量名来指示变量的数据类型吗?
可以。在变量名中指出数据类型已经成为今天的大型复杂系统中普遍使用的一条规则。通常,变量类型由一个或两个字符表示,并且这些字符将作为变量名的前缀。使用这一技术的一种广为人知的命名规则就是匈牙利命名法,它的名称来自于Microsoft公司的程序员CharlesSimonyi。表19.2列出了一些常用的前缀。
表1 9.2一些常用的匈牙利命名法前缀
---------------------------------------------------------------------------------
数据类型 前缀 例子
---------------------------------------------------------------------------------
char c clnChar
int i iReturnValue
long l lNumRecs
string sz szlnputString ( 以零字节结束 )
int array ai aiErrorNumbers
char * psz pszInputString
---------------------------------------------------------------------------------
象Microsoft Windows这样的环境,就大量使用了匈牙利命名法或其派生体。其它一些第四代环境,例如Visual Basic和Access,也采用了匈牙利命名法的一种变体。
在编写程序时,你不必拘泥于一种特定的命名法——你完全可以建立自己的派生命名法,非凡是在为自己的typedef命名时。例如,有一个名为SOURCEFILE的typedef,用来保存源文件名、句柄、行号、最后编译日期和时间、错误号等信息。你可以引入一个类似“sf”(sourcefile)的前缀符号,这样,当你看到一个名为sfBuffer的变量时,你就会知道该变量保存了SOURCEFILE结构中的部分内容。
不管怎样,在命名变量或函数时,引入某种形式的命名规则是一个好主意,尤其是当你与其它程序员共同开发一个大的项目时,或者在Microsoft Windows这样的环境下工作时。采用一种认真设计好的命名规则将有助于增强你的程序的可读性,尤其是当你的程序非常复杂时。
请参见:
19.1 应该在变量名中使用下划线吗?
19.5 什么是骆驼式命名法?
19.6 较长的变量名会影响程序的速度、大小或效率吗?
19.9 一个变量名应该使用多少个字母?ANSI标准答应有多少个有效字符?
19.10 什么是匈牙利式命名法?应该使用它吗?
19.3 使用注释会影响程序的速度、大小或效率吗?
不会。当你的程序被编译时,所有的注释都会被忽略掉,只有可执行的语句才会被分析,并且被放入最终编译所得的程序版本中。
因为注释并不会给程序的速度、大小或效率带来负担,所以你应该尽量多使用注释。你应该在每一个程序模块的头部都加上一段注释,以解释该模块的作用和有关的非凡事项。同样,你也要为每一个函数加上注释,其中应包括作者姓名、编写日期、修改日期和原因、参数使用指导、函数描述等信息。这些信息将帮助其它程序员更好地理解你的程序,也有助于你以后回忆起一些要害的实现思想。
在源代码中也应该使用注释(在语句之间)。例如,假如有一部分代码比较复杂,或者你觉得有些地方要进一步说明,你就应该毫不犹豫地在这些代码中加入注释。这样做可能会花费一点时间,但这将为你或其它人节省几个小时的宝贵时间,因为只需看一下注释,人们就能马上知道你的意图。
在19.4中有一个例子,它表明了使用注释、空白符和下划线命名规则是如伺使程序更清楚、更易懂的。
请参见:
19.4 使用空白符会影响程序的速度、大小或效率吗?
19.6 较长的变量名会影响程序的速度、大小或效率吗?
19.4 使用空白符会影响程序的速度、大小或效率吗?
不会。与注释一样,所有的空白符都会被编译程序忽略掉。当你的程序被编译时,所有的空白符都会忽略掉,只有可执行的语句才会被分析,并且被放入最终编译所得的程序版本中。
在C程序中用空白符隔开可执行语句、函数和注释等,将有助于提高程序的可读性和清楚度。许多时候,只要在语句之间加入空行,就可提高程序的可读性。请看下面的这段代码:
/ * clcpy by GBlansten * /
void clcpy(EMP * e,int rh,int ot)
{ e->grspy= (e->rt * rh)+ (e->rt * ot * 1.5) ;
e->txamt = e->grspy * e->txrt ;
e->ntpy = e->grspy-e->txamt ;
updacctdata (e);
if (e->dd= =false) cutpyck
(e) ;
else prtstb (e) ; }
你可以看到,这个函数确实是一团糟。尽管这个函数显然是正确的,但恐怕这个世界上没有一个程序员愿意去维护这样的代码。假如采用本章中的一些命名规则(例如使用下划线,少用一些短而模糊的名字),使用一些大括号技巧,加入一些空白符和注释,那么这个函数将会是下面这个样子:
/********************************************************************************/
Function Name: calc_pay
Parameters: emp -EMPLOYEE pointer that points to employee data
reg-hours -The number of regular hours (<=40) employee
has worked
ot-hours -The number of overtime hours (>40) employee
has worked
Author : Gern Blansten
Date Written: 13 dec 1993
Modification: 04 sep 1994 by Lloyd E. Work
-Rewrote function to make it readable by human beings.
Des cription: This function calculates an employee's gross bay ,tax
amount, and net pay, and either prints a paycheck for the
employee or (in the case of those who have direct deposit)
prints a paycheck stub.
/*********************************************************************************/
void calc_pay (EMPLOYEE * emp, int reg hours, int or_hours)
{
/ * gross_pay = (employee rate * regular hours)+
(employee rate * overtime hours * 1.5) * /
emp->gross_pay= (emp->rate * reg_hours) +
(emp->rate * ot hours* 1.5);
/ * tax amount=gross_pay * employee's tax rate * /
emp->tax amount=emp->gross_pay * emp->tax-rate ;
/ * net pay=gross pay-tax amount * /
emp->net-pay=emp->gross pay-emp->tax_amount ;
/ * update the accounting data * /
update accounting data(emp);
/ * check for direct deposit * /
if (emp->direct_deposit= =false)
cut_ paycheck(emp); / * print a paycheck * /
else
print_paystub(emp); /* print a paycheck stub * /
}
你可以看到,Lloyd版本(该版本中使用了大量的注释、空行、描述性变量名等)的可读性比糟糕的Gern版本要强得多。
你应该尽量在你认为合适的地方使用空白符(和注释符等),这将大大提高程序的可读性一一当然,这可能会延长你的工作时间。
请参见:
19.3 使用注释会影响程序的速度、大小或效率吗?
19.6 较长的变量名会影响程序的速度、大小或效率吗?
19.5 什么是骆驼式命名法?
骆驼式命令法,正如它的名称所表示的那样,是指混合使用大小写字母来构成变量和函数的名字。例如,下面是分别用骆驼式命名法和下划线法命名的同一个函数:
PrintEmployeePaychecks();
print employee paychecks();
第一个函数名使用了骆驼式命名法——函数名中的每一个逻辑断点都有一个大写字母来标记;第二个函数名使用了下划线法----函数名中的每一个逻辑断点都有一个下划线来标记。
骆驼式命名法近年来越来越流行了,在许多新的函数库和Microsoft Windows这样的环境中,它使用得当相多。另一方面,下划线法是c出现后开始流行起来的,在许多旧的程序和UNIX这样的环境中,它的使用非常普遍。
请参见:
19.1 应该在变量名中使用下划线吗?
19.2 可以用变量名来指示变量的数据类型吗?
19.6 较长的变量名会影响程序的速度、大小或效率吗?
19.9 一个变量名应该使用多少个字母?ANSI标准答应有多少个有效字符?
19.10 什么是匈牙利式命名法?应该使用它吗?
19.6 较长的变量名会影响程序的速度、大小或效率吗?
不会,当你的程序被编译时,每一个变量名和函数名都会被转换为一个“符号”——对原变量或原函数的一种较短的符号性的表示。因此,无论你使用下面的哪一个函数名,结果都是一样的:
PrintOutAllTheClientsMonthEndReports();
prt_rpts();
一般说来,你应该使用描述性的函数名和变量名,这样可以加强程序的可读性。你可以查阅编译程序文档,看一下答应有多少个有效字符,大多数ANSI编译程序答应有至少31个有效字符。也就是说,只有变量名或函数名的前31个字符的唯一性会被检查,其余的字符将被忽略掉。
一种较好的经验是使函数名或变量名读起来符合英语习惯,就好象你在读一本书一样——人们应该能读懂你的函数名或变量名,并且能很轻易地识别它们并知道它们的大概作用。
请参见:
19.1 应该在变量名中使用下划线吗?
19.2 可以用变量名来指示变量的数据类型吗?
19.3 使用注释会影响程序的速度、大小或效率吗?
19.4 使用空白符会影响程序的速度、大小或效率吗?
19.5 什么是骆驼式命名法?
19.9 一个变量名应该使用多少个字母?ANSI标准答应有多少个有效字符?
19.10 什么是匈牙利式命名法?应该使用它吗?
19.7 给函数命名的正确方法是什么?
函数名一般应该以一个动词开始,以一个名词结束,这种方法符合英语的一般规则。下面列出了几个命名比较合适的函数:
PrintReports();
SpawnUtilityProgram();
ExitSystem();
Initia|izeDisk():
请注重,在这些例子中,函数名都以一个动词开始,以一个名词结束。假如按英语习惯来读这些函数名,你会发现它们其实就是:
print the reports(打印报告)
spawn the utility program(生成实用程序)
exit the system(退出系统)
initialize the disk(初始化磁盘)
使用动词一名词规则(非凡是在英语国家)能有效地加强程序的可读性,并且使程序看起来更熟悉。
请参见:
19.5 什么是骆驼式命名法?
19.8 作用大括号的正确方法是什么?
19.10 什么是匈牙利式命名法?应该使用它吗?
19.8 使用大括号的正确方法是什么?
在C中,使用大括号的方法无所谓对还是错——只要每个开括号后都有一个闭括号,你的程序中就不再会出现与大括号有关的问题。然而,有三种闻名的大括号格式经常被使用:
Kernighan和Ritchie,Allman,Whitesmiths。下文中将讨论这三种格式。
在《C程序设计语言(The C Programming Language)》一书中,Brian Kernighan和Dennis Ritchie介绍了他们所使用的大括号格式,这种格式如下所示:
if (argc<3) {
printf (" Error! Not enough arguments. Correct usage is ..\n" ) ;
printf("c:>eopyfile <source_file> <destination_file>\n") ;
exit (1) ;
}
else {
open_files () ;
w
hile (! feof(infile)) {
read_data ( ) ;
write_data() ;
}
close files() ;
}
注重,在Kb&R格式中,开括号总是与使用它的语句在同一行上,而闭括号总是在它所关闭的语句的下一行上,并且与该语句对齐。例如,在上例中,if语句的开括号和它在同一行上,|f语句的闭括号在它的下一行上,并且与它对齐。在与if语句对应的else条件语句以及出现在程序段后部的while语句中,情况也是这样的。
下面是用Allman格式书写的同一个例子:
if (argc<3)
{
printf("Error! Not enough arguments. Correct usage is :\n" ) ;
printf("C:>copyfile <source_file> <destination_file>\n") ;
exit(1);
}
else
{
open_files ( );
while (! feof(infile))
{
read_data ( ) ;
write data();
}
close_files() ;
}
注重,在Allman格式中,每个大括号都单独成行,并且开括号和闭括号都与使用它们的语句对齐。
下面是用Whitesmiths格式书写的同一个例子:
if (argc<3)
{
printf("Error! Not enough arguments, Correct usage is :\n" );
printf ("C :> copyfile<source_file><destination_file>\n." ) ;
exit(1);
}
else
{
open files () ;
while (! feof(infile))
{
read_data() ;
write data();
}
close files () ;
}
与Allman格式相同,Whitesmiths格式也要求大括号单独成行,但是它们要和它们所包含的语句对齐。例如,在上例中,if语句的开括号是与第一个printf()函数调用对齐的。
不管你使用哪一种格式,一定要保持前后一致——这将有助于你自己或其它人更方便地读你的程序。
请参见:
19.5 什么是骆驼式命名法?
19.7 给函数命名的正确方法是什么?
19.10 什么是匈牙利式命名法?应该使用它吗?
19.9 一个变量名应该使用多少个字母?ANSI标准答应有多少个有效字符?
一般说来,变量名或函数名应该足够长,以有效地描述所命名的变量或函数。应该避免使用短而模糊的名字,因为它们在别人理解你的程序时会带来麻烦。例如,不要使用象这样的短而模糊的函数名:
opndatfls();
而应该使用更长一些的函数名,象下面这样:
open data_files();
或者:
OpenDataFiles();
这对变量名也是同样适用的。例如,与其使用这样一个短而模糊的变量名:
fmem
不如将其扩展为完整的描述:
free_memory_available
使用扩展了的名字会使程序更易读,更易理解。大多数ANSI编译程序答应有至少31个有效字符——即只有变量或函数名的前31个字符的唯一性会被检查。
一种较好的经验是使函数名或变量名读起来符合英语习惯,就好象你在读一本书一样一人们应该能读懂你的函数名或变量名,并且能很轻易地识别它们并知道它们的大概作用。
请参见:
19.1 应该在变量名中使用下划线吗?
19.2 可以用变量名来指示变量的数据类型吗?
19.5 什么是骆驼式命名法?
19.6 较长的变量名会影响程序的速度、大小或效率吗?
19.10 什么是匈牙利式命名法?应该使用它吗?
19.10 什么是匈牙利式命名法?应该使用它吗?
匈牙利命名法是由Microsoft公司的程序员Charles Simonyi(无疑是个匈牙利人的后裔)提出的。在这种命名法中,变量名或函数名要加上一个或两个字符的前缀,用来表示变量或函数的数据类型。
这种命名法有许多好处,它被广泛应用于象Microsoft Windows这样的环境中。关于匈牙利命名法的具体解释以及其中的一些命名标准,请参见19.2。
请参见:
19.1 应该在变量名中使用下划线吗?
19.2 可以用变量名指示变量的数据类型吗?
19.5 什么是骆驼式命名法?
19.6 较长的变量名会影响程序的速度、大小或效率吗?
19.9 一个变量名应该使用多少个字母?ANSI标准答应有多少个有效字符?
19.11 什么是重复处理(iterative processing)?
重复处理是指反复执行相同的程序语句,但可能会在满足某个条件时退出循环。c语言提供了一些现成的结构来实现重复处理,例如while循环,do…while循环和for循环。在这些结构中,当某个条件为真时,预先定义的一批语句将被反复执行。下面是一个重复处理的例子:
while (x<lO0)
{
y=O;
do {
for(z =O;z<lOO;z++)
y++ ;
}while (y<1000) ;
x++;
}
在这个例子中,包含在while循环中的语句被执行100次,在while循环中还有一个do…while循环,在do…whlie循环中的for循环被执行10次;在for循环中,变量y作100次自增运算。因此,语句
y++;
总共被执行100,000次(100次while×10次do…while×100次for)。然而,在while循环结束时,y并不是100,000,因为每循环1000次后y都会被置为o。
在c程序中,重复处理的应用是非常广泛的,例如你经常要用重复处理来读写数组或文件。下面的程序用重复处理来读入并向屏幕打印你的AUTOEXEC.BAT文件:
# include <stdio. h>
# include <stdlib. h>
int main(viod) ;
int main (void)
{
FILE * autoexec_file ;
char buffer[250] ;
if ( (autoexec_file = fopen (" C : \\ AUTOEXEC. BAT", "rt ") ) = = NULL )
{
{printf (stderr,"Cannot open AUTOEXEC. BAT file. \n") ;
exit(1) ;
printf("Contents of AUTOEXEC. BAT file : \n\n" ) ;
while(! feof(autoexec file))
{
fgets (buffer, 200,autoexee_file) ;
printf(" %s" ,buffer) ;
}
felose (autoexee_file) ;
rerun(0) ;
}
注重,上例用一条while语句来反复地调用fgets()和printf()函数,以读入AUTOEXEC.BAT文件中的每一行,并把它们打印到屏幕上。这仅仅是如何使用重复处理的例子之一。
请参见:
19.12 什么是递归(recursion)?怎样使用递归?
19.12 什么是递归(recursion)?怎样使用递归?
在c语言中,一个调用自身(不管是直接地还是间接地)的函数被称为是递归的(recursive)。你可能不明白究竟为什么一个函数要调用自身,要解释这种情况,最好先举一个例子。一个经典的马上可以举出来的例子就是计算整数的阶乘。为了计算一个整数的阶乘值,你要用这个数(x)乘以它的前一个数(X一1),并且一直乘下去,直到到达1。例如,5的阶乘可以这样来计算:
5*4*3*2*1
假如X是5,你可以把这个算式转换为一个等式:
X!=X*(X-1)*(X-2)*(X-3)*(X-4)*1
为了用C语言完成这项计算任务,你可以编写一个名为calc_factorial()的函数,它反复调用自身,每次都把被计算的值减1,直到到达1。下面的例子说明怎样编写这个calc_factorial()函数:
#include<stdio.h>
void main(void);
unsigned lon
g calc_factorial(unsigned long x);
void main(void)
{
int x=5;
printf("The factorial of %d is %ld. \n" ,x,calc_factorial(x));
}
unsigned long calc_factorial(unsigned long x)
{
if(! x)
return 1L ;
return(x * calc_factorial(x-1L)) ;
}
在上例中,calc_factorial()在调用自身前要先把x的值减去1。假如x等于O,if语句的条件将为真,calc factorial()将不再被递归调用。因此,当被计算的值到达O时,calc_factorial()作完最后一次递归调用并退出,其返回值为1。返回1是因为任何值都可以安全地和1相乘,并仍能保持其原来的值。假如程序中包含下述语句:
x=calc_factorial(5);
它将开展为:
x=5*(5-1)*(4-1)*(3-1)*(2-1)*1;
因此,x将等于5的阶乘,即120。
递归是一个简洁的概念,同时也是一种很有用的手段。但是,使用递归是要付出代价的。与直接的语句(如while循环)相比,递归函数会耗费更多的运行时间,并且要占用大量的栈空间。递归函数每次调用自身时,都需要把它的状态存到栈中,以便在它调用完自身后,程序可以返回到它原来的状态。未经精心设计的递归函数总是会带来麻烦。
假如可能的话,你应该避免使用递归函数。例如,前文中的阶乘函数可以写成下面这种形式:
# include <stdio. h>
void main(void) ;
unsigned long calc factorial(unsigned long x);
void main (void)
{
int x=5;
printf("The factorial of %d is %ld. \n" ,x ,calc_factorial (x)) ;
}
unsigned long calc-factorial(unsigned long x)
{
unsigned long factorial;
factorial=x;
while (x>1L)
{
factorial * =--x;
}
return (factorial);
}
这个版本的calc_factorial()函数用一个while循环来计算一个值的阶乘,它不仅比递归版本快得多,而且只占用很小的栈空间。
请参见:
19.11 什么是重复处理(iterative processing)?
19.13 在C语言中,表示真和假的最好方法是什么?
在c语言中,任何等于零的东西都被认为是假,任何等于非零值的东西都被认为是真,因此,最常见的定义就是假为O,真为1。许多程序中都包含了具有如下定义的头文件:
#define FALSE O
#define TRUE 1
假如你在编写Windows程序,你应该注重头文件windows.h中的TRUE和FALSE的确切定义。上述真和假的定义方式非常普遍,并且是完全可以接受的,然而,还有其它几种定义方式,请看下例:
#define FALSE 0
#define TRUE !FALSE
上例把FALSE定义为0,把TRUE定义为非零值。注重,即使是负数,如-1,也是非零值,因此也被认为是真。
另一种定义方式是建立自己的枚举类型,如Boolean(或者BOOL),如下所示:
enurn BOOL{
FALSE,
TRUE
};
正象你所可能已经知道的那样,在缺省情况下,枚举类型的第一个元素被赋值为O,因此,在上述枚举定义中,FALSE被赋值为0,TRUE被赋值为1。与使用符号常量相比,使用枚举类型有它的一些好处,详见5.6和5.7中的有关内容。
哪种方法最好呢?这个问题没有一个唯一的答案。假如你在编写一个Windows程序,那么TRUE和FALSE都是已经为定义好的,你没有必要再建立自己的定义,在其它情况下,你可以从前文所介绍的几种方法中选择一种。
请参见:
5.6 用enum要害字说明常量有什么好处?
5.7 与用#define指令说明常量相比,用enunl要害字说明常量有什么好处?
19.14 空循环(null loops)和无穷循环(infinite loops)有什么区别?
空循环并不会无休止地进行下去——在重复预先指定的次数后,它就会退出循环。无穷循环会无休止地进行下去,并且永远不会退出循环。把空循环和无穷循环对比一下,就能很好地说明它们之间的区别。
下面是一个空循环的例子:
for(x=O;x<500000;x++);
注重,在上例中,在for循环的闭括号后直接加入了一个分号。正如你可能已经知道的那样,c语言并不要求在for循环后加分号,通常只有包含在for循环中的语句后面才会带分号。
在for循环后面直接加入分号(并且不使用大括号),即可建立一个空循环——实际上是一个不包含任何语句的循环。在上例中,当for循环执行时,变量x将自增500,000次,而在每一次自增运算期间,没有进行任何处理。
那么,空循环有什么用呢?在大多数情况下,它的作用就是在程序中设置一次暂停。前面的例子将使程序“暂停”一段时间,即计算机数到500,000所需的时间。然而,空循环还有更多的用处,请看下例:
while(!kbhit());
这个例子用一个空循环来等待一次击键操作。当程序需要显示类似"Press Any Key ToContinue"这样的信息时,这种方法是很有用的(假设你的用户很聪明,不会执着地在键盘上寻找"Any Key"!)。
无穷循环与空循环不同,它永远不会结束。下面是一个无穷循环的例子:
while(1);
在这个例子中,while语句中包含了一个非零常量,因此,while的条件永远为真,循环永远不会结束。注重,在闭括号后面直接加入一个分号,因此while语句中不包含任何其它语句,循环将无法终止(除非终止程序)。
请参见:
19.15 continue和break有什么区别?
19.15 continue和break有什么区别?
continue语句用来返回循环的起始处,而break语句用来退出循环。例如,下例中就有一条典型的continue语句:
while(!feof(infile))
{
fread(inbuffer,80,1,infile);/*read in a line from input file*/
if(!strncmpi(inbuffer,"REM",3)) /*check if it is
a comment line*/
continue; /*it's a comment,so jump back to the while()*/
else
parse_line(); /*not a comment—parse this line*/
}
上例读入一个文件并对其进行分析。“REM(remark的缩写)”用来标识正在被处理的文件中的一个注释行。因为注释行对程序不起任何作用,所以可以跳过它。在读入输入文件的每一行时,上例就把该行的前三个字母与"REM"进行比较。假如匹配,则该行就是注释行,于是就用continue语句返回到while语句,继续读入输入文件的下一行;否则,该行就是一条有效语句,于是就调用parse_line()函数对其进行分析。
break语句用来退出循环。下面是一个使用break语句的例子:
while (! feof(infile))
fread(inbuffer,80,1,infile) ;/* read in a line from input file * /
if (! strncmpi (inbuffer,"REM",3)) / * check if it is
a comment line * /
continue; /* it's a comment, so jump back to
the while() * /
else
{
if (parse_line()==FATAL_ERROR) / * attempt to parse
this line * /
break; /* fatal error occurred,so exit the loop * /
}
这个例子建立在使用continue语句的那个例子的基础上。注重,在这个例子中,要检查parse_line()函数的返回值。假如parse_line()的返回值为FATAL_ERROR,就通过break语句立即退出while循环,并将控制权交给循环后面的第一条语句。
请参见:
19.14 空循环(null loops)和无穷循环(infinite loops)有什么区别?
Word教程网 | Excel教程网 | Dreamweaver教程网 | Fireworks教程网 | PPT教程网 | FLASH教程网 | PS教程网 |
HTML教程网 | DIV CSS教程网 | FLASH AS教程网 | ACCESS教程网 | SQL SERVER教程网 | C语言教程网 | JAVASCRIPT教程网 |
ASP教程网 | ASP.NET教程网 | CorelDraw教程网 |