计算机能够直接识别的是0和1的二进制编码,早期程序编码也是用二进制编码的机器语言来编写的。机器语言的每一操作码在计算机内部都有相应的电路来完成,可以直接在对应的机器上运行,不需要任何翻译,执行速度快。不同的计算机都有各自的机器语言,即指令系统。不同型号的计算机其机器语言是不相通的,按照一种计算机的机器指令编制的程序,不能在另一种计算机上执行。
假定,0000代表加法,0010代表减法;0000代表寄存器Ax,0001代表寄存器Bx;0000代表加载,0001表示存储。指令中前四位表示操作符,中间四位表示寄存器,最后16位表示数。
如果我们想要计算机实现计算1+2的值,采用机器语言步骤如下。
(1)将数1送入到CPU中的寄存器Ax中。
0001000000000001
(2)将寄存器Ax和数2相加,求得和值放回寄存器Ax中。
0000000000000010
现在,我们编写的是1+2的求和的计算,编码里全部是0和1的二进制。如果我们要设计的是Windows里自带的计算器呢,大家可以想象那将是满屏的0和1数字,若不是专业人员根本没有办法编写,也没有办法读,更谈不上修改了,由此可以知道机器语言的写、读和修改异常困难,程序编写的效率极其低下。
鉴于机器语言的编程困难,于是出现了汇编语言。汇编语言是一种符号语言,采用易于记忆的英文单词缩写代替机器语言的0和1的编码,例如用ADD表示加法,用SUB表示减法,用MOV表示将数送到寄存器中。
如果我们想要计算机实现计算1+2的值,采用汇编语言步骤如下。
(1)将1存入计算机(寄存器AX)
MOV AX,1
(2)将AX=AX+2
ADD AX,2
用汇编语言进行程序编写比用机器语言要方便些,但其本质上还是一种面向机器的语言,编写困难容易出错。程序员编写计算机程序需要考虑具体的机器,面对不同的机器需要编写不同的程序代码。
采用机器语言和汇编语言进行的程序设计都是属于面向机器的程序设计。面向机器的程序设计的思维方式和人类考虑问题的思维方式相差甚远,在程序设计时都是针对特定的机器,逐一执行,可移植性差。
随着计算机价格的不断下降、硬件环境不断改善,应用范围不断扩大,面向机器的编程方法太关注机器本身的操作指令、存储等方面,已经越来越不适合编写程序的需求。为解决这一问题,科学家前辈发展出了更接近人类思维习惯的面向过程的语言。面向过程的语言中用人们习惯的标识来表示指令中的操作符和操作数,例如用“+”号表示加法,用sum标识符来表示和值,使得程序中的语句能够尽可能做到见其名知其意。相比面向机器的思想来说,面向过程是一次思想上的飞跃,面向过程的程序设计不再关注机器本身,而是关注怎样一步一步地解决具体的问题,即解决问题的过程。20世纪60年代为解决第一次软件危机出现的结构化程序设计的思想(Structured Programing,SP)便是面向过程的程序设计思想的集中体现。
结构化程序设计思想是最早由E.W.Dijikstr在1965年提出的,20世纪70年代趋于成熟,是整个20世纪80年代主要的程序设计方法。SP的核心设计思想是“自顶而下,逐步求精”。一个大的系统项目按照功能要求分解成若干个子项目功能模块,子项目模块进一步分解为若干个子子项目模块,如此重复,从上往下进行分解,直到每一个子子模块能都轻易解决为止,使得问题由复杂变得简单。
SP中的每一个子模块只允许有一个入口和一个出口,内部均是由顺序、选择和循环三种基本结构组成。
顺序结构是最简单的程序结构,也是最常用的结构,程序中的各操作是按照它们出现的先后顺序执行的。如图3.1所示,当执行完第一条语句后执行第2条语句,直到所有 n 条语句执行完毕。
图3.1 顺序结构
例:计算圆的面积。用标识 r 表示圆的半径, area 表示圆的面积。
设计步骤:
(1)定义变量 r 存放圆的半径,定义变量 area 存放圆的面积。
(2)通过键盘输入圆的半径 r 。
(3)通过公式3.14* r * r 计算圆的面积并存放到 area 中。
(4)输出圆的面积。
选择结构是根据判断某个条件是否成立,选择其中的一个分支执行。如图3.2所示,当表达式的值为真时即表达式判断条件成立则执行语句1,当表达式条件不成立执行语句2。
例:判断一个人是否成年。
分析:根据民法第十七条规定十八周岁以上的自然人为成年人,也就是说人的年龄大于等于18岁就是成年人了。在设计中,用age表示一个人的年龄,判断age大于等于18是否成立,若条件成立则为成年,输出为成年人,若条件不成立则是未成年,输出未成年人。
图3.2 选择结构
用C语言写的代码如下:
选择结构一般分为单分支、双分支、多分支结构。
循环结构表示重复执行某个或某些操作,直到某条件为假(或为真)时才可终止循环。循环结构中最主要的是分析哪些操作需要反复执行,在何种条件下需要反复执行。在循环结构中将需要反复执行的操作称为循环体,将能够使得判断条件变成不成立的量称为循环变量,要求在循环体中有语句能够改变循环变量的值,使得判断条件能够不成立。循环结构有当型循环和直到型循环两种基本形式。
当型循环。如图3.3所示,先执行判断条件,若条件成立则继续执行循环体,执行完循环体再次执行判断条件,若条件还成立继续执行循环体,直到判断条件不成立才终止循环。因为是“当条件满足时执行循环”,即先判断后执行,所以称为当型循环。
直到型循环。如图3.4所示,先执行循环体,循环体执行完后执行判断条件,若条件成立则再次执行循环体,直到条件不成立时才终止循环。因为是“直到条件不成立时为止”,即先执行后判断,所以称为直到型循环。
图3.3 当型循环结构图
图3.4 直到型循环结构
例:求1+2+3+…+10的和。
分析:先定义一个变量存放和值,初值为0,后将1到10的数字依次累加到和值里,这样就可以求得1到10的和值。用变量sum表示和值,初值为0,用变量i表示1到10的某个数,初值为1,步骤如下:
图3.5 求1到10的和
(1)sum ←0,i←1
(2)将1和和值sum相加再存回sum,即sum=sum+i
i的值1已经累加到和sum里,将i增加1变成2,即i=i+1
(3)将2和和值sum相加再存回sum,即sum=sum+i
i的值2已经累加到和sum里,将i增加1变成3,即i=i+1
(4)将3和和值sum相加再存回sum,即sum=sum+i
i的值3已经累加到和sum里,将i增加1变成4,即i=i+1
……
(10)将10和和值sum相加再存回sum,即sum=sum+i
i的值10已经累加到和sum里,将i增加1变成11,即i=i+1
这时已将1到10的相加并存放在和值sum里,计算结束。
由上述分析可以知道,需要重复的部分是“sum=sum+i;i=i+1”;即循环体为“sum=sum+i;i=i+1;”,判断条件为“i<=10”。流程图如图3.5所示。
用C语言编码如下:
结构化程序中每一个子项目可以完成某一独立功能,可以用函数来表示。在结构化程序设计中函数是指一段可以直接被另一段程序或代码引用的程序或代码,也叫子程序或方法。很多高级语言中都有子程序的概念。C语言中程序主要由主函数和若干个函数构成,主函数是程序的入口,由主函数调用其他函数,其他函数之间也可以相互调用。
在C语言中函数定义如下。
函数类型 函数名(形参列表)
若编写求1到1 000以内某一个整数的和的功能,在C语言中用一个函数表示这个功能,要想求得1到某一个数的和,首先要知道这个数是什么,可以将这个数作为函数的参数,参数类型为整型。调用函数最终要得到的是和值,可以作为和值函数返回值,函数类型为整型。函数体可以用循环结构求解。
用C语言编码实现“1到100内某一个整数的和”的函数如下。
编写main主函数,调用sum函数求1到100的和,代码如下。
在该例中,有两个函数main和sum函数,在主函数main中调用sum求1到100的和。
SP方法设计思想清晰,符合人们处理问题的习惯,易学易用。模块层次分明,便于分工开发和调试,程序可读性强。
结构化程序思想编程在相当程度上缓和了软件危机,然而随着计算机硬件的迅速发展,计算机业务应用及需求越来越复杂,结构化思想越来越跟不上硬件和业务的发展,很快出现了第二次软件危机。这时的大型软件经常由数百万行代码构成,参与其中的程序员也数以百计,怎样高效、可靠地构造和维护这样的大型软件成了一个新的难题。利用面向过程编程思想设计的软件,并不能很好地满足这样的需求。在这种情况下,面向对象的编程思想开始发展起来。
面向对象程序设计(Object-Oriented Programming,OOP)与结构化程序设计完全不同,面向对象的方法学用人们在实际生活中的思维方式来认识、理解和描述事物,认为任何事物都是对象,世界由各种对象组成,复杂的对象可由简单的对象以某种方式组成。将具有共同特征的对象分为一类,概括出其共有的特征抽象成类,面向对象程序设计的基石是对象和类。类是一组具有相同数据结构和相同操作的对象的描述;对象是某一类的实例。典型的面向对象方法具有抽象、封装、继承和多态性四个特征。
关于面向对象程序设计在后面章节里有详细介绍。