第1章 基本数据与表达式
程序设计语言是人指挥计算机工作的工具。C++语言功能强大,使用灵活,是目前工程中应用比较广泛的一种高级程序设计语言。本章介绍高级程序设计语言的基本概念、C++语言的基本语法单位及表达式运算。
1.1 概述
C++语言源于C语言。C语言诞生于20世纪70年代,最初设计的目的是编写操作系统。因为C语言规则简单,不但具有高级语言的数据表示、运算功能,还可以直接对内存操作,程序运行效率高。基于以上优点,C语言很快成为世界流行的程序设计语言。
然而,人们要求计算机解决的问题越来越多,C语言在处理大问题、复杂问题时表现出来的弱点也越来越明显,例如,缺乏数据类型检查机制,代码重用性差等。
20世纪80年代,美国AT&T贝尔实验室对C语言进行扩充改版,成为C++语言。C++语言保持了C语言原有的高效、简洁的特点,强化了数据的类型检查和语句的结构性,增加了面向对象程序设计的支持。由于C++语言的灵活性、良好的继承性和前瞻性,许多软件公司都为C++语言设计编译系统,提供不同级别的应用类库以及方便实用的开发环境,使C++语言得到广泛应用。
1.1.1 程序设计与程序设计语言
在人类社会生活中,“语言”是人与人之间用来表达意思、交流思想的工具,是由语音、词汇和语法构成的一定系统。人类的思维、感情相当丰富,所以,人类的语言系统非常复杂。甚至同一个词、同一个句子,在不同的环境下、以不同的语气表达,都可能解释成完全不同的意思。
“程序设计语言”是人指挥计算机工作的工具。它是一种工程语言,由字、词和语法规则构成的指令系统。一种高级程序设计语言往往只有一百多条词汇、若干条规则。
高级语言提供了常用的数据描述和对数据操作的规则描述。这些规则是“脱机”的,程序员只需要专注于问题的求解,不必关心机器内部结构和实现。我们说的“程序设计语言”一般是指高级语言。
计算机对问题的求解方式通常可以用数学模型抽象。随着社会科学的发展,人们要求计算机处理的问题越来越复杂,计算机工作者不断寻求简洁可靠的软件开发方法。从过程化、结构化到近代出现的面向对象程序设计,体现了程序设计理论、方法的不断发展。
用高级语言编写的程序称为“源程序”。计算机不能直接识别源程序,必须翻译成二进制代码才能在机器上运行。一旦编译成功,目标程序就可以反复高速执行。
程序设计就是根据特定的问题,使用某种程序设计语言,设计出计算机执行的指令序列。程序设计是一项创造性的工作,根据任务主要完成以下两方面工作。
(1)数据描述
数据描述是指把被处理的信息描述成计算机可以接受的数据形式,如整数、实数、字符、数组等。
信息可以用人工或自动化装置进行记录、解释和处理。使用计算机进行信息处理时,这些信息必须转换成可以被机器识别的“数据”,如:数字、文字、图形、声音等。不管什么数据,计算机都以二进制数的形式进行存储和加工处理。数据是信息的载体,信息依靠数据来表达。
有一些数据,可以直接用程序设计语言的“数据类型”描述,如:数值、字符。另外一些数据,虽然一般的程序设计语言没有提供直接定义,但许多开发商都会提供相应的处理工具。例如,Visual Studio .NET Framework类库提供了丰富的多媒体数据处理方法,可以在界面或程序代码中使用或处理图形、声音等数据。
(2)数据的处理
数据处理是指对数据进行输入、输出、整理、计算、存储、维护等一系列活动。数据处理的目的是为了提取所需的数据成分,获得有用的资料。
程序设计语言的规则都是围绕描述数据、操作数据而设计的。在结构化程序设计中,数据的描述和处理是分离的。用面向对象方法,程序对数据和处理进行封装。按照人们习惯的思维模式和软件重用原则,对象还具有继承、多态等特性。每种程序设计方法都有自己的一套理论框架,相应的设计、分析、建模方法,都有各自的优缺点。采用什么方法设计程序,应该依据问题的性质、规模、特点进行选择。世界上没有一种能解决所有问题的最优方法。
学习C++语言,不仅为了掌握一种实用的计算机软件设计工具,更重要的是,通过该课程学习,掌握计算机程序设计语言的基本语法规则,掌握结构化程序设计和面向对象程序设计的基本方法,为进一步学习和应用打下良好基础。
1.1.2 一个简单的C++程序
问题:输入圆的半径,求圆的周长和面积。
【例1-1】方法一,用结构化方法编程。
数据描述:半径、周长、面积均用浮点型数据表示。
数据处理:
输入半径r; 计算周长 =2*π*r; 计算面积 =π*r*r; 输出半径,周长,面积。
可以编写如下程序:
#include<iostream> using namespace std; int main() { double r,girth,area; //说明数据 const double PI = 3.1415; cout << "Please input radius:\n"; cin>>r; //输入半径 girth=2*PI*r; //计算周长 area=PI*r*r; //计算面积 cout<<"radius="<<r<<endl; //输出数据 cout << "girth = " << girth << endl; cout << "area = " << area << endl; }
上述程序运行后,屏幕显示:
Please input radius:
用户输入:
6.23
程序继续执行,计算并输出结果:
radius = 6.23 girth = 39.1431 area = 121.931
若再次运行程序,可以输入不同的半径值,求得不同圆的周长和面积。
这个程序很容易读懂。第1行称为预编译指令,说明该程序要使用的外部文件。C++语言标准头文件iostream包含了程序常用的输入cin和输出cout的定义。
第2行是使用名空间的声明。using和namespace都是关键字,std是系统提供的标准命名空间。详细说明见3.8节。
C++语言以函数为程序运行的基本单位,函数的一般形式为:
类型 函数名 (参数表) { 语句序列 }
“函数名”是标识符,用于识别和调用函数。用户自定义函数由程序员命名。一个程序可以由多个文件组成,一个文件可以包含多个函数。每个程序必须有一个,而且只有一个主函数,因为主函数是由系统启动的。最简单的程序只由主函数构成。main是系统规定的主函数名。
“函数名”之前的“类型”表示函数运行返回表达式值的数据类型。C++主函数返回类型一般为int或void。
“函数名”之后一对圆括号相括的是函数参数。如果没有参数,圆括号也不能省略,它是C++函数的标识。函数名、函数返回类型和参数表组成C++的函数头(或称为函数首部)。
函数头之后以一对花括号相括的“语句序列”构成函数体。C++语句以分号结束,一行可以写多条语句,一条语句可以分多行写。程序按语句序列执行。
花括号也可以出现在语句序列中。这时,花括号相括的语句称为复合语句或语句块。根据语句的功能不同,有说明语句、执行语句、流程控制语句等。
以双斜杠“//”开始的文本为程序注释,放置在行末。以“/*…*/”相括的注释文本可以放置在程序的任何位置。注释内容不是执行代码,用于增加程序的可读性。系统只显示注释内容,不予编译。
有关函数定义和使用,参见第3章的相关内容。
【例1-2】方法二,用面向对象方法编程。
当我们用对象思维考虑问题时,可以对问题进一步抽象。所有称为“圆”的这种类型的几何图形,最基本的要素是半径。它决定了圆的大小,也是区分具体圆A、圆B、圆C等的基本数据。一旦定义了具体的有半径值的圆,就有它特定的周长和面积了。
“圆”是一种类型。在面向对象方法中,称为“类类型”或“类”。“圆”类型的基本数据是“半径”。类的数据称为“属性”或“数据成员”。
数据成员有了具体的值之后,就可以计算周长和面积了。这种“计算”由程序代码实现,并且“封装”在类中,称为类的“方法”或“成员函数”。
下面是用这种方法编写的C++程序:
#include<iostream> using namespace std; class Circle //说明类 { double radius; //类的数据成员 public : //类的成员函数 void Set_Radius( double r ) { radius = r; } double Get_Radius() {return radius;} double Get_Girth() {return 2*3.14*radius;} double Get_Area() {return 3.14*radius*radius;} }; int main() { Circle A,B; //说明对象 A.Set_Radius( 6.23 ); cout << "A.Radius = " << A.Get_Radius() << endl; cout << "A.Girth = " << A.Get_Girth() << endl; cout << "A.Area = " << A.Get_Area() << endl; B.Set_Radius( 10.5 ); cout << "B.radius = " << B.Get_Radius() << endl; cout << "B.Girth=" << B.Get_Girth() << endl; cout << "B.Area = " << B.Get_Area() << endl; }
程序运行结果:
A.Radius = 6.23 A.Girth = 39.1244 A.Area = 121.873 B.Radius = 10.5 B.Girth = 65.94 B.Area = 346.185
该例程首先说明一个类Circle。类中数据成员radius用于定义半径。成员函数Set_Radius用于设置半径的值,Get_Radius获取半径,Get_Girth计算并返回圆周长,Get_Area计算并返回圆面积。
主函数中说明了圆类Circle的两个圆:A和B。A和B称为Circle类的实例或对象。main函数中由对象调用成员函数输出两个圆的半径、周长和面积。
这个程序比例1-1看起来要烦琐一些。但是,以Circle类为基础,可以很方便地派生新的类。新的类对原有类的特性不需要重定义,可以自己定义新的数据,例如,指定圆心坐标,填充圆的颜色;派生出球体、圆柱体等新的几何体。每个新类都可以拥有自己的成员函数,实现自己特有的功能,这是结构化程序设计方法所做不到的。面向对象技术提供了软件重用、解决大问题和复杂问题的有效途径。
1.1.3 程序的编译执行
用高级语言编写的程序称为“源程序”。源程序是文本文件,便于阅读修改。C++的.cpp文件是文本文件,可以用各种字处理工具打开和编辑。计算机不能直接识别源程序,必须翻译成二进制代码才能在机器上运行。翻译方式有两种:一种称为解释方式,另一种称为编译方式。解释方式是指由“解释程序”对源程序逐条语句地一边翻译,一边执行。这种方式执行速度慢,便于观察调试程序。编译方式是指由“编译程序”把源程序全部翻译成二进制代码。编译后的程序称为“目标程序”,可以反复高速运行。每一种高级语言都配有解释或编译系统。
C++提供编译执行方式。实现一个C++语言源程序主要经过以下3个步骤。
1.编辑
使用C++语言编辑器或其他文字编辑器录入源程序。若使用C++语言编辑器,则系统自动生成.cpp文件扩展名;若使用其他文字编辑器,则只有以.cpp为扩展名的文件才能被C++语言识别。.cpp文件是文本文件。
2.编译
把一个.cpp文件编译成.exe目标文件,要经过预处理、编译和连接3个步骤:预处理的作用是执行程序编译之前的准备,例如执行包含指令、宏替换命令;然后编译器对程序进行语法检查,如果发现语法错误,则显示错误信息,让程序员修改,直至正确,生成目标代码;最后把目标代码进行连接处理,往往还会加入一些系统提供的库文件代码。
这些步骤在集成开发环境中会自动完成。
3.运行
VC.NET用文件夹管理应用程序。经过编译后,应用程序文件夹中有一个扩展名为.sln的解决方案文件,需要在C++环境下执行。还生成一个debug文件夹,里面有一个.exe文件,可以直接在操作系统(如DOS,Windows)环境下执行。为了便于测试程序,C++提供了强有力的跟踪调试和错误处理功能。源程序和目标程序都能够作为文件永久保存。
编写源程序难免存在一些错误,这些错误可以分成以下4类。
① 编译错误:在编译源程序时发现的语法错误。例如,表达式(a+b*(c-d)缺少了右括号。
② 连接错误:在程序编译之后,进行连接时出现的错误。例如,找不到连接库文件。
③ 运行错误:执行目标程序时发现的错误。例如,执行标准函数sqrt(x),求x的平方根,而x的值为负数。
④ 逻辑错误:编译和运行时均不能发现的错误。例如,执行表达式2/4,期望值是0.5,但C++作整除运算,结果为0。
一个程序经常要经过反复的调试、验证会才能完善,投入使用。因此,编写的程序应该力求达到以下目标。
① 正确性:这要求程序员熟悉所使用的程序设计语言,避免语法、语义上的错误;设计简单易行的算法达到预期目的;对复杂的问题,则应考虑使用有效的程序设计方法。
② 易读性:一个程序结构清晰易读,才能便于查错,便于修改。一个程序模块耦合度低、接口清晰,才便于代码的重用。
③ 健壮性:当输入或运行出现数据错误时,程序能够做出适当的反应或进行处理,而不会产生莫名其妙的结果。
④ 运行高效率:程序运行时间较短,而且占用的存储空间较小。
为达到以上目标,需要我们在不断学习和实践中提高程序设计水平。“程序”是人的智力产品。从理论上说,程序是永远不会损坏的。实际上,程序在整个生存周期都会根据需要进行修改、维护,都可能产生错误。所有的硬件产品都允许有误差,但程序错误是不允许的,它有时甚至会产生悲剧性的后果。程序的生产和维护比硬件产品复杂得多。所以,计算机科学界期望有一套工程化的方法进行程序的开发维护。为了体现这种工程思想,程序就要伴随着一套开发、维护、使用的文档。程序加上这些相关文档称为软件。