程序设计语言基础.docx
《程序设计语言基础.docx》由会员分享,可在线阅读,更多相关《程序设计语言基础.docx(32页珍藏版)》请在冰豆网上搜索。
程序设计语言基础
程序设计语言基础
先来认识一下程序,要使计算机能完成人们预定的工作,就必须把要完成工作的具体步骤编写成计算机能执行的一条条指令,计算机执行这些指令序列后,就能完成指定的功能,这样的指令序列就是程序。
简单地说,程序是能完成一定功能的指令序列。
要想学会编写程序,首先要学习能提供指令的程序设计语言;其次要学习更多和程序设计有关的知识和技巧,就好像认识许多字不一定能写出好文章一样,仅仅学习了程序设计语言还不能编写出好的程序。
程序的功能一般是指其处理数据的能力,所以一个程序包括以下两个方面的内容。
(1)对数据的描述。
在程序中要指定处理数据的类型和组织形式,即数据结构(datastructure)。
(2)对操作的描述。
即操作步骤,也就是算法(algorithm)。
数据是操作的对象,操作的目的是对数据进行加工处理,以得到期望的结果。
作为程序设计人员,必须认真考虑和设计数据结构与操作步骤(即算法)。
因此,著名计算机科学家沃思(NikiklausWirth)提出一个公式:
程序=数据结构+算法
当然这些要素都离不开一个与计算机交互的平台——语言工具和环境。
因此,可以这样表示程序:
程序=算法+数据结构+语言工具和环境
算法是程序的灵魂,是解决问题所需要采用的合适方法,决定程序“做什么”和“怎么做”;数据结构是加工对象的组织方式;程序设计语言是程序设计的工具和环境。
大家更熟悉的一个词可能是“软件”,软件是具有一定综合功能的程序、数据及相关文档的集合。
只有打好程序设计的基本功,并掌握一定的软件开发技术后,才有可能去开发具有实用性的软件。
1.1引言
1.1.1程序设计语言及其分类
1.什么是程序设计语言?
其功能又如何
“程序设计语言是一种指挥机器的工具?
一种程序员之间交流的方式?
一种表述高层设计的媒介?
一种算法的记述方式?
一种表述观念间关系的途径?
一种试验工具?
一种控制计算机化的设备的途径?
我的观点是,一种通用程序设计语言必须是所有这些东西,这样才能服务于它缤纷繁杂的用户集合。
”——这是Stroustrup[1994]对程序设计语言的论述。
程序设计语言是一种记法,它们被用做计算过程的描述、组织和推导。
发明它的目的就是为了使机器更容易使用。
程序设计语言是计算机软件中非常独特的一部分,它属于系统软件,但又和应用软件息息相关。
它的作用是使人类能够用某些命令、指令去让计算机为人类进行数值、逻辑运算。
2.程序设计语言可以按对硬件依赖的程度分类
人们把程序设计语言按其与计算机硬件依赖的程度分为低级语言和高级语言。
低级语言包括机器语言和汇编语言。
机器语言就是一台机器本身的语言,是这台机器可以直接响应的指令的记述形式,是唯一可以被计算机直接执行的语言。
面向机器程序语言的指令由许多的0、1组成,一条计算机指令指示计算机一次完成一个最基本的操作。
由于这种语言编写的程序冗长、可读性差、移植性差,容易出错,晦涩难懂,是一般人所无法接受的语言。
但这样的程序冗余小,执行效率高,节省内存,运行速度快,所以一般用于直接控制计算机的硬件。
为了克服机器语言的缺点,汇编语言应运而生。
汇编语言是机器语言的一种变形,它是将机器指令助记成为可读易懂的符号,但仍只能完成机器层次的操作。
用汇编语言编写的程序要在计算机上执行,先要将用汇编语言编写的源程序转换成机器语言程序,完成这个转换功能的程序称为“汇编程序”。
低级语言的缺点是:
指令功能简单,即使完成一个算术表达式的运算也需编写大段程序,而且需要对硬件进行了解,完成的程序不具有可移植性。
低级语言的优点是:
执行速度快,可直接控制硬件,适用于实时性要求较高的自动控制系统。
为了克服以上两种语言的缺陷,产生了许多高级语言。
高级语言的共同特点是:
完全不依赖于硬件,是接近于自然语言(当然是英语)记法的程序设计语言。
其基本构成是语句,而语句的功能要比机器语言指令的功能强大得多,另外还提供了丰富的函数库。
3.程序设计语言还可以按其采用的范型分类
(1)面向过程的语言
面向过程的语言虽可独立于计算机编写程序,但用这类语言编写程序时,程序不仅要说明做什么,更重要的是要非常详细地告诉计算机如何做,程序需要详细描述解题的过程和细节。
(2)面向问题的语言
不必关心问题的求解算法和求解的过程,只需指出问题是做什么,数据的输入和输出形式,就能得到所需结果。
面向问题语言又称为非过程化语言或陈述性语言,如报表语言、SQL(StructuredQueryLanguage)语言等。
SQL语言是数据库查询和操纵语言,能直接使用数据库管理系统。
使用面向问题语言解题只要告诉计算机做什么,不必告诉计算机如何做。
(3)面向对象的语言
为克服面向过程语言过分强调求解过程的细节,程序不易复用的缺点,产生了面向对象程序设计方法和面向对象语言。
面向对象语言引入了对象、消息、类、继承、封装、抽象和多态性等机制和概念。
用面向对象语言进行程序设计时,以问题域中的对象为基础,将具有类似性质的对象抽象成类,并利用继承机制,仅对差异进行程序设计,可以提高软件开发效率。
4.其他分类方式
按应用领域分类有人工智能程序设计语言(如lisp)、逻辑推理程序设计语言(如Prolog)和系统程序设计语言(如C语言)。
命令式程序设计语言,由于其适用性强、应用范围广、语句简捷、灵活而得到广泛的使用,如Pascal、Basic、Fortran和C等都属于这类语言。
程序设计初学者一般首先学习的就是命令式程序设计语言。
程序设计语言只是程序设计的工具,通过对一种程序设计语言的学习,掌握了程序设计的思想方法后是可以触类旁通的。
1.1.2程序的执行
高级程序设计语言接近于自然语言,用其编写的程序对人而言可读性是增强了,但其实现是靠机器来完成的,因此机器与高级程序之间需要一个“翻译”——就是要把高级语言转化为机器能读懂的指令。
就像现实中的翻译有口译(同声翻译)和笔译两种形式一样,程序的翻译也有两种方式:
解释和编译。
解释就像口译一样,解释一句执行一句,不保留翻译结果;编译和笔译一样,是把一个程序全部翻译并保存翻译结果,以后机器直接运行的是翻译后的结果。
用高级程序设计语言编写的程序称为源程序;经编译生成后的机器可识别的程序称为目标程序;最后经过对目标程序进行链接(详见3.2.3节),生成的是可脱离编译环境,在操作系统下执行的程序称为可执行程序。
多数高级程序设计语言采用编译方式,也有的高级程序设计语言,既可以是解释方式,也可以是编译方式。
C语言采用的是编译方式。
目前流行的C语言编译系统有以下几个版本。
∙MicrosoftC(或称MSC)
∙BorlandTurboC(或称TurboC)
∙AT&TC
这些C语言版本不仅实现了ANSIC标准,而且在此基础上各自作了一些扩充。
本书主要针对其标准(共同)的部分,以TurboC为例进行讲解。
附录C、附录D中以TurboC为例,介绍了程序设计环境和函数库。
高级语言系统不仅提供编译功能,还有很好的编程环境。
在该环境下,可以对程序进行编辑、编译、链接、调试和运行等工作(详见附录D)。
还提供了将编译、链接和运行三项工作集成完成的命令(或菜单),TurboC对编辑好的源程序只需单击菜单RUN,就对程序进行编译、链接和运行的全部工作。
这在方便编程人员的同时,容易让人误解,以为编辑好的程序可以直接运行。
程序需要先编译再运行这个基本常识,可以使读者对程序设计语言的某些语法现象有深入的了解,必须引起注意。
1.2数据及其类型
前面已经讨论过程序的主要功能就是处理数据,那么C语言能够处理哪些类型的数据?
又是如何表示它们的?
下面进行介绍。
1.2.1数据类型
首先介绍C程序设计语言中,可以存储和处理的数据类型,如图1-1所示。
图1-1数据类型
1.2.2数据类型的作用
通过数据类型的定义,决定了该类型数据的存储空间的大小和存储方式,进而决定了该类数据的取值范围和精度。
另外,数据类型还决定了数据运算(操作)的规则,这一点在1.2.3节介绍运算符时会予以详细说明。
不同类型数据的取值范围如下。
表1-1整数表
数据类型描述符
占用字节数
取值范围
有符号整数
短
int
shortint
2
–32 768~+32 767
长
long
longint
4
–2 147 483 648~2 147 483 647
无符号整数
短
unsigned
unsignedint
unsignedshort
2
0~65 535
长
unsignedlong
4
0~4 294 967 295
表1-2实数表
单精度实型
float
4
±(3.4e–38~3.4e+38)
6位精度
双精度实型
double
8
±(1.7e–308~1.7e+308)
16位精度
【注意事项】
(1)当计算结果超出范围时,其他高级程序设计语言,输出的结果以“*”代表,提示程序设计人员改写程序中的数据类型。
而C语言的输出方式,不容易发现这类错误,因为它输出的是溢出以后(忽略超过存储空间的进位)的数据结果,例:
执行inta=32767;b=a+1;printf("%d",b);的输出为–32 768。
显然输出的结果与真实结果完全背离,因此,读者在编程时一定要认真分析实际问题中数据可能的范围,并依此来选择数据类型。
(2)对于实型数据除了有数据范围的限制,还有精度的概念。
对正常范围的整型数据计算机是精确存储的,但对实型数据计算机就不能精确存储了。
虽然float实型数据范围是±(3.4e–38~3.4e+38),但计算机认为:
1234567(f)等于1234566(f)、1e–7等于0、0.1234567等于0.1234568…
这就是表1-2中所描述的6位精度。
这同样是由于存储空间有限造成的。
(3)数据类型还决定了数据运算,如一般语言都限定只对整数进行求余运算,C语言对整数的求余运行符为“%”,另外C语言还提供了对实型数据求余的函数fmod(x,y)。
(4)C语言支持不同类型数据的混合运算,运算结果类型由参与运算的数据决定。
C语言规定同类型数据运算结果类型不变,如整数与整数运算的结果一定是整数,所以4/5的运算结果为0。
不同类型数据运算时,运算结果取高一级的数据类型(图1-1中自上而下,类型由低到高)。
算式1/2*2.22的值为0,而非1.11;而1.0/2*2.22的值才为1.11。
1.2.3数据表示——常量、变量
数据一般以常量(或符号常量)和变量两种基本的形式在程序中出现。
1.常量
常量是在程序运行过程中不可改变的量,其类型根据其书写形式和范围决定。
(1)整型常量(常量后缀:
L或l表示长整型数、U或u表示无符号数)
∙十进制整数(基本数字0~9):
110、456、139L、32769U和233445(为长整型)等。
∙八进制整数(基本数字0~7,以0打头):
037、010L、–026和0776等。
∙十六进制整数(基本数字0~9,而10~15记为A~F,以0X打头):
0X331、0X、0X3AC0和–0XAF等。
(2)实型常量(常量后缀:
F或f表示浮点数)
实型也称为浮点型。
实型常量也称为实数或者浮点数。
在C语言中,实数只采用十进制。
它有十进制小数形式和指数形式两种形式。
∙十进制小数形式:
由数码0~9和小数点组成(后缀为“f”或“F”即表示该数为浮点数)。
例如:
0.0、25.0、5.789、0.13、5.0、300、-267.8230、234F、67f等
均为合法的实数。
∙指数形式:
由十进制数,加阶码标志“e”或“E”以及阶码(只能为整数,可以带符号)组成。
其一般形式为:
aEn(a为十进制数,n为十进制整数)
其值为a*10n。
如:
2.1E5(等于2.1*105)3.7E-2(等于3.7*10-2)
0.5E7(等于0.5*107)-2.8E-2(等于-2.8*10-2)
以下是不合法的实数:
345(无小数点)E7(阶码标志E之前无数字)
-5(无阶码标志)53-E3(负号位置不对)2.7E(无阶码)
【注意事项】
(1)数学意义上的常量在程序设计语言中不一定是常量,如1/2、π和e(自然数)等。
特别是23%,在程序设计语言中既不是常量,也不是后面将介绍的表达式。
(2)单精度浮点型,有效位数只有7位。
双精度型,有效位为16位。
但TurboC规定小数后最多保留6位,其余部分四舍五入。
(3)字符常数。
字符常数通常就是将单个字符写在一对单引号内表示,如'a'、'A'、'7'、'0'等。
C语言提供一些特殊意义的转义字符,它们被当做一个单字符,也是字符常数。
转义字符包括反斜线、转义字符和一对单引号等,如表1-3所示。
表1-3转义字符表
符号序列
名称
符号序列
名称
\n
回车换行
\'
单引号
\t
水平制表
\"
双引号
\b
退格
\\
反斜线
\r
回车不换行
\ddd
八进制ASCII码值(0~377)
\f
换页
\xdd
十六进制ASCII码值(0~F9)
字符类型的数据和数值类型的数据存储方式是不同的。
字符类型是以其ASCII码的二进制方式存储的(参见附录5),每个字符占1个字节,字符 'a' 的ASCII码是97,存储它占一个字节。
而数值类型是按类型分配存储空间的,整型的97、197和1297等都是占2个字节。
字符类型与数值类型的操作方式也是有区别的。
大多数程序设计语言规定,字符类型的数字只是一个符号,不能参与算术运算。
但在C语言中允许字符以ASCII码值参与算术运算,其结果以字符模式或数值模式输出。
例如:
'A'的ASCII码为65,printf("%d",'A'+3);的输出结果为68,printf("%c",'A'+3);的输出结果为D。
(4)字符串常量
字符串常量是一个字符序列,且被括在双引号中。
字符串的语法形式是"characters"。
characters可以是0或多个字符集中的字符,包括任意转义字符。
其中若出现双引号、反斜线或回车换行符必须用其转义字符(\",\\,\n)来表示。
不可显示的字符也是用相应的转义字符表示。
每个转义字符均被看做一个单字符。
例如:
"123"、"Cprogram"和"11.11%" 等都是合法的字符串常量。
字符常量占一个字节的内存空间。
字符串常量占的内存字节数等于字符串中字符的个数加1。
增加的一个字节中存放字符"\0"(ASCII码为0)。
这是字符串结束的标志。
例如:
字符常量'a'和字符串常量"a"虽然都只有一个字符,但在内存中的情况是不同的。
'a'在内存中占一个字节,可表示为:
a
"a"在内存中占两个字节,可表示为:
a
\0
(5)符号常量
符号常量就其表面意思就是用符号代表的常量。
一般用大写字母做符号常量。
C语言是通过宏来定义符号常量的,如#definePI3.1415926定义后,程序中所出现的PI,在程序编译时将被3.1415926替换。
详见第3章的3.4.1节。
2.变量
1)变量、变量名
表面上理解“变量”就是可以改变的量。
就其实质而言,变量就是数据的存储空间。
变量之所以能改变,就像一个房间可以换不同的人住宿一样,变量存储空间中的内容是可以更改的。
变量的存储空间是开辟在内存中的,我们无须清楚它具体的物理地址,只要知道变量的逻辑名称——变量名就可以使用它了。
变量名是对数据存储空间的一个抽象名称,它一方面代表存储空间或其地址(表示方式:
&变量名,&为C语言的地址符);另一方面又代表其中存储的数据(表示方式:
变量名本身),因此通过变量名就可以对它空间中的内容进行改变或引用。
C语言的变量名命名规则是“以字母或下划线开头的,字母、数字或下划线的序列”。
变量名可以是任意长度,但编译器只识别31个或更少(因编译系统不同而不同)。
C语言的关键词是不可以作为变量名的,参见附录A中有关标识符的内容。
【注意事项】
在对变量名命名时应注意:
(1)所有语言都允许26个英文大小写字母出现在变量名中,特别地要注意C语言认为A与a是不同的变量,即C语言的变量名是区分大小写的。
(2)变量名最好与其所存储的数据意义有关联,这样可增加程序的可读性。
如“累加”和用sum或s做变量名、“姓名”用name或xm做变量名、圆周率(3.1415926)用PI做变量名等。
(3)变量名最好不要用到字母l(小写l)、o、z I(大写I)等易与数字混淆的字母。
2)变量定义及赋初值
变量需先定义后使用。
所谓变量定义就是说明变量类型,其功能是为说明的每一个变量按类型开辟存储空间(编译系统在对程序进行“编译时”,根据变量定义的类型为其分配逻辑空间,运行时分配物理的内存空间)。
从而决定其存储数据的范围,参与运算的种类等。
变量定义的格式如下:
变量类型描述符变量表;
其中变量类型描述是指C语言允许使用的有效类型,而变量表是由一个或多个被定义的变量名组成,若定义多个变量,则变量之间用“,”分隔。
特别的,C语言可以定义常变量,即程序中不可改变其值的变量。
其定义的格式如下:
const变量类型描述符变量表;
向变量空间中存储数据的方法很多,在后面会有介绍,为了更好地理解变量的意义,下面先来认识其中的一种方法。
变量=算术表达式;("="称为赋值号,不是等号)
称为赋值语句,操作过程为先计算表达式的值,然后将数值存储在变量中。
例如:
inta;a=8;a=9;a=a+8;,执行这些语句的功能是,先为变量a开辟2个字节的整型数据存储空间,然后存入8,变量值为8;再将9存入变量a,以前存入的8被覆盖,变量值为9。
第三个赋值语句,右边是一个表达式,要先计算其值,取变量a的值为9,9+8=17,将17存入变量a,变量的值就变成了17。
在定义变量的同时,还可以对其中全部或部分的变量赋初始值,例如:
inti,j,k=1,s=0,n=k+6,m;
【注意事项】
变量使用时要注意:
(1)变量类型的选择是根据其所存储数据的逻辑意义决定的。
如工资一般是实型数据又不会太大,相关变量应该定义为float型;年龄,身高等数据一般为整型且不会很大,相关变量应该定义为int型。
当有些整型数据或其运行结果较大时,可以考虑定义为长整型。
当整型意义的数据或结果很大时,如n!
、1+2+22+23+…+2n等,在不考虑精度的情况下,应考虑用实型变量存储数据或运算结果。
当数据很大而且需要很高的精度时,可参见5.5节,学习关于高精度数据的处理方法。
(2)变量除了需要先定义后使用外,还必须先赋值后引用。
例如:
inti;i=i+1;
经过定义后的变量i,可以存储数据了,但在计算i+1时,要注意:
其他程序设计语言认为这是语法错误,在编译时会指出变量没有赋初始值的错误,只有改正后程序才能通过编译,然后运行。
而C语言则不做错误指示,即可以通过编译,那么它又是怎么运行的呢?
很简单,C语言就是将i空间“原有”的值加1后再赋给i。
那么“原有的”值是什么呢?
哪儿来的?
有计算机基础的人都知道,当删除一个文件时,这个文件其实并没有真正被删除,只是在文件目录中对该文件做一个删除“标记”,文件内容仍保留在原来的空间中。
若该文件空间没有被占用,只需去掉删除“标记”就可将文件恢复。
程序运行时要进入内存,执行完就“退出”内存。
后一个程序运行时,可能正好被分配到这部分内存空间,这些空间确实是可用的,但不是真正意义的“空白空间”,和文件空间一样原来程序的内容并没有被清零,所以变量“原有”的值就是在该程序之前占用此空间的软件代码或数据的值,我们无法知道它具体是什么。
因此一定要注意:
“变量必须先定义后使用”。
为此程序设计语言还提供了在变量定义的同时对其赋初始值的功能,如inti=0,a=6;。
(3)初学者在编写程序时,程序中经常出现变量意义混淆,变量使用混乱的情况。
建议初学者在编程时养成以下良好的习惯。
①对有固定意义的信息用固定的变量名,如循环变量一般用i、j、k;问题的规模(问题中要处理数据的数量),如人员的数量等用变量m或n等。
在程序首部加注释语句,说明每个变量的意义,这样对程序以后的维护也非常有好处。
注释语句的格式为/*……*/。
注释语句可以出现在程序的任意位置,与程序的运行没有任何关系。
3)变量的作用
初学者往往不明白什么时候用常量表示数据,什么时候该用变量方式表示数据。
举几个简单的例子来说明。
下面的程序是求半径为1.234 567 cm的圆的周长和面积。
printf()的功能是计算并输出计算结果。
若不用变量程序1如下。
程序1:
main()
{printf("L=%f",2*3.1415926*1.234567);
printf("s=%f",3.1415926*1.234567*1.234567);
}
程序1不但书写起来麻烦、易出错,读起来也不好懂。
使用变量后,再看程序2。
程序2:
main()
{floatpi=3.1415926,r=1.234567;
printf("L=%f",2*pi*r);
printf("s=%f",pi*r*r);
}
像数学上的代数一样,引入变量后程序简洁,克服了程序1的缺点。
再来看下一个程序——程序3会有哪些改进呢?
程序3:
main()
{floatpi=3.1415926,r=1.234567,temp;
temp=pi*r;
printf("L=%f",2*temp);
printf("s=%f",temp*r);
}
程序中引入临时变量temp,用来记录pi*r的值,这样在以后的程序中就减少了重复的乘法运算。
当然由于临时变量的引入同时降低了程序的可读性,鉴于现代计算机运行速度的提高和计算机资源的普及,读者在程序书写时可以在时间效率和可读性之间权衡利弊。
其次若不引入变量,以上程序都只能求半径为1.234 567cm的圆的周长和面积,而不方便对其他半径的圆进行求解。
引入变量并通过键盘输入语句,可以使程序得到优化——增强程序的通用性。
程序4如下。
程序4:
main()
{floatpi=3.1415926,r;
scanf("%f",&r);
printf("L=%f",2*pi*r);
printf("s=%f",pi*r*r);
}
这个程序在执行到scanf("%f",&r);语句时暂停执行,等待用户从键盘输入圆的半径,用户输入任何半径程序都能计算出相应的周长和面积。
这几个例子并不能概括变量的全部作用,但至少可以理解如下几点。
引入变量可以减少对常量的录入,不但提高了编写程序的效率,还可能减少录入错误。
因为编译系统不可能发现常量的拼写错误,而若变量拼写错误,系统会因变量没有进行说明而报错的。
对某些数据不直接使用常量,而引入变量通过键盘输入语句为其赋值,可以使程序的通用性更强。
引入临时变量来记录运算的中间结果,可减少运算,从而提高程序运行的时间效率。
1.3程序结构
1.3.1程序基本构成
1.函数
C语言源程序由函数构成,函数又由程序设计语言提供的具有一定功能的语句构成。
一个源程序中必不可少且只能有一个的是主函数(main函数)。
在第3章之前只针对仅包含主函数的程序进行讨论。
为了说明C语言源程序结构的特点,先看一个简单的程序,来表现C语言源程序基本组成结构。
虽然有关内