经济管理中C++程序设计
上QQ阅读APP看书,第一时间看更新

第1部分 面向过程程序设计

第1章 C++语言基础

软件运行离不开数据。日常生活中我们将数字、文字等数据输入计算机中,然后用各种计算机程序处理这些数据。数据有常量和变量之分,常量是指在程序运行过程中值保持不变的量;变量是指在程序运行过程中,其值可以随时改变的量。常量和变量都属于某种数据类型。此外,处理数据需要进行运算,C++语言提供了丰富的运算符,例如进行算术计算、比较值的大小、修改变量、逻辑地组合关系等。本章将介绍这些C++语言编程的基础组成成分,包括数据类型、运算符和表达式等。

1.1 引言

20世纪发明的计算机到21世纪有了飞跃性的发展,各种形式的智能设备紧密联系,为企业生产和人民生活带来了便利。在不同场合使用的计算机(或智能设备),都由硬件和软件组成。如果没有软件,那只不过是一个空壳子。软件也就是计算机程序是指一组指示计算机每一步动作的指令,通常用某种程序设计语言编写,运行于某种目标体系结构的计算机上。打个比方,一个程序就像一个用汉语(程序设计语言)写下的红烧肉菜谱(程序),用于指导懂汉语和烹饪手法的人来做这个菜。计算机程序是通过在计算机内存中开辟一块存储空间,并用一个语句序列不断修改这块存储空间上的内容,最终得到问题的解答来解决实际问题的。

人和计算机交流,也需要解决语言问题,需要创造一种计算机和人都识别的语言,这就是计算机语言。通过使用跟人类自然语言接近的高级程序设计语言在程序中表达我们的旨意,程序则负责调度各种计算机资源完成我们下达的旨意。计算机语言通过定义变量的形式给出了申请内存的方式,并通过表达式和赋值语句给出了对内存中的数据进行运算和修改的方法,通过分支和循环语句提供了用不同方式安排语句序列的能力。大部分计算机语言还提供了基础函数库完成一些常用的计算和数据处理的功能。本书将带领大家系统地学习C++语言。

1.2 编写C++程序

1.一个简单的C++程序

我们经常使用计算机来进行各种生活或工作中的数学运算,下面我们就来展示一个用C++语言编写的简单计算机程序。

大家刚开始学习看不懂这段程序没关系,我们大致地从上往下分析一下这段代码的含义。首先是第一行#include<iostream>,意味着我们在写这段程序时,包含了另外一个已经写好的iostream文件,这个文件可以让我们和计算机进行输入输出。第2行代码可以让我们使用名为std的namespace中的标识符,如程序中的cin、cout。第3行代码是程序的主函数,它是程序执行的入口。第5行和第6行定义了三个变量,分别表示第一个运算数、第二个运算数和运算符。第7行是向屏幕输出一行文字,进行用户提示的。第8行是接收用户输入的数字和符号,并赋值给相应的变量。第9行是一个开关逻辑,根据你输入运算符的不同,决定接下来执行哪个运算,也就是执行下面的哪一个case语句。第11行到第29行就是分情况进行相应的具体计算了,稍微特殊的是除法/的情况,会判断第二个运算数是否为0。第31行程序执行到这里就正常结束了。

2.用C++进行输入和输出

计算机语言比如C++可以实现让我们人类与机器进行交互,交互最基本方式体现为我们可以通过键盘向其输入数据,计算机在进行处理运算之后可以通过屏幕输出结果。C++语言已经实现了输入输出功能,我们要做的就是正确地调用。

输入和输出是将数据从计算机外部设备传送到计算机内存或反向传送的过程,数据如流水一样从一处流向另一处。C++中形象地将此过程称为流(Stream)。C++提供了用于输入输出的iostream类库,iostream这个单词由3个部分组成,即i-o-stream,意为input输入-output输出-stream流。

类库iostream包含了对输入输出流进行操作所需的基本信息,因此大多数C++程序都包括iostream。在iostream文件中定义了我们常用的两个流对象,cin对应来自键盘的标准输入流,cout对应发往屏幕的标准输出流。cin通常与>>符号结合在一起,用于将键盘输入的数据分配给相应的变量;而cout通常与<<符号结合在一起,用于将数据向屏幕进行输出。有一个简单而形象的方法理解运算符<<和>>的作用:它们指出了数据移动的方向。

例如>>a箭头方向表示把数据放入a中。而<<a箭头方向表示从a中拿出数据。大家可以参考一下先前的例子。

1.3 常量

常量是指在程序运行过程中,其值不能被改变的量,如数据2,–56,3.14,0.22,3.16E7和'hello'都是常量。常量可分为整型常量、浮点型常量、布尔常量、字符常量、字符串常量和符号常量。

1.整型常量

例如整数6,–45和978都是整型常量。C++把不含小数点和指数的数当作整数,因此7.0和0.314159e1则不是整型常量。大多数整型常量看作int类型。如果整数特别大,则有不同的处理。整型常量分为八进制整型常量、十进制整型常量和十六进制整型常量三种表示形式。其表示方法如表1.1所示。

表1.1 整型常量的表示方法

例如,固定资产的最低折旧年限如下:

(1)房屋、建筑物,为20年,用八进制表示为024年,十六进制表示为0x14年;

(2)飞机、火车、轮船、机器、机械和其他生产设备,为10年,用八进制表示为012年,十六进制表示为0xa年;

(3)与生产经营活动有关的器具、工具、家具等,为5年;

(4)飞机、火车、轮船以外的运输工具,为4年;

(5)电子设备,为3年。

2.浮点型常量

浮点数差不多可以和数学中实数概念相对应。实数包含了整数之间的那些数。例如:2.75,3.16E7,7.00和2e–8都是浮点数。注意,加了小数点的数是浮点型值,所以7是整型常量,而7.00是浮点型常量。显然,浮点数只采用十进制,并且书写浮点数有多种形式。浮点型常量有两种表示形式:一种是十进制小数形式,另一种是指数形式。

1)十进制小数形式

十进制小数形式为包含一个小数点的十进制数字串。例如:车辆购置税税率0.10,一般纳税人增值税税率0.17等。需要注意的是,此类浮点型常量小数点前或后可以没有数字,但不能同时没有数字。下面是更多的有效的浮点型常量:300.,.2。

2)指数形式

指数形式的格式由两部分组成:十进制小数形式或十进制整型常量部分和指数部分。其中指数部分是在e或E(相当于数学中幂底数10,后文中均用e)后跟整数阶码(即可带符号的整数指数)。需要注意的是,要求e或E前必须有数字,E或e后面的阶码必须为整数,且浮点型常量中不能出现空格。

例如:

2013年国家财政收入129143亿元,可以表示为1.29e13元。

也可以表示为0.129143e14亿元或者129e-1兆亿元。

但不可以表示为如下形式:

e13缺少十进制小数部分。

1. 29e缺少阶码。

1. 29e-13.2不是整数阶码。

1. 29e13浮点型常量中出现空格。

【例1-1】A企业持一张面额100万元,尚有120天到期的商业票据到银行贴现,如果银行规定的贴现率为6%,则银行应付款给A企业多少钱?

问题分析

贴现是指银行承兑汇票的持票人在汇票到期日前,为了取得资金,贴付一定利息将票据权利转让给银行的票据行为,是持票人向银行融通资金的一种方式。贴现息、贴现净额的计算公式如下:

贴现息=票据到期值×贴现年利率×贴现天数/360天

贴现净额=票据到期值–贴现息

根据上述公式,A企业应支付贴现息为6%×120/360,银行最终支付A企业贴现净额为100×(1–6%×120/360)=98(万元)

编写程序

运行结果

      银行应付款:980000

默认情况下,编译器将浮点型常量当作double类型(通常使用8个字节进行存储)。例如,假设是一个float变量(通常使用4个字节进行存储),执行下面的语句:

      Result=3.0*5.0;

其中3.0和5.0被存储为double类型,乘积运算使用双精度,运算后的结果被截尾转换为float类型。将浮点型常量当作double类型能保证计算精度,但是会减慢程序的执行。

如果需要类型为float类型的浮点型常量,可以通过f或F后缀来定义,比如3.1f和4.32E5F,编译器会把这种浮点型常量当作float类型。

3.布尔常量

布尔常量有两个值,一个是true,代表“真”;另一个是false,代表“假”。

4.字符常量

字符常量,是用一对单引号括起来的单一字符。例如:'a','b','=','+','?'都是合法字符常量。字符常量属于char类型,在计算机的存储中占据一个字节。单引号是定界符,并不是字符常量的一部分。一个字符常量代表ASCII字符集中的一个字符,它的值即为该字符对应的ASCII码值。例如,在ASCII字符集中,字符'A'的ASCII码值为65。字符常量存储在计算机存储单元中时,并不是存储字符本身,而是以其代码(一般采用ASCII码)存储的,例如字符'A'的存储单元中存放的是65(以二进制形式存放)。一个字符常量也是一个整数,字符常量一般用来与其他字符进行比较,但也可以像其他整数一样参与数值运算。

字符常量有以下特点:

(1)区分大小写:单引号中的大小写字母代表不同的字符常量,例如'A'与'a'是不同的字符常量。

(2)单引号中的空格符也是一个字符常量。

(3)字符常量只能包括一个字符,不能是字符串,所以'ab'是非法的。

(4)字符常量只能用单引号括起来,不能用双引号。例如"a"不是一个字符常量而是一个字符串。

(5)区分数字与数字字符。例如,'5'和5是不同的,'5'是字符常量,其ASCII值为53;5是整型常量,数值大小为5。

字符常量包括两种类型,普通字符和转义字符。

普通字符,用一对单引号括起来,前面例子中的'a','b','=','+','?'都是普通字符。

转义字符,就是表示特定意义的字符,以\开头的字符序列,后跟一个或几个字符。当然也要用一对单引号括起来。转义字符具有特定的含义,不同于字符原有的意义,故称“转义”字符。转义字符主要用来表示那些用一般字符不便于表示的控制代码,常用的转义字符如表1.2所示。

表1.2 常用转义字符表

表中的转义字符具体含义:

转义序列\n,\t,\v,\b和\r是常用的输出设备控制字符。换行符\n可替换endl,使光标移到下一行的开始处。水平制表符\t将当前位置移到下一个水平制表位置(通常为字符位置1,9,17,25等)。垂直制表符\v将当前位置移到下一个垂直制表对齐点。退格符\b使光标在当前行上退回一个空格。回车符\r使光标回到当前行的开始处。

字符常量\是转义字符的前缀,'是字符常量的定界符,"是字符串常量的定界符,所以在字面上直接使用他们时会造成混乱,通过表中的三个转义序列\\、\'和\"可以输出字符常量\、'和"。例如要打印下面这行内容:

      The teacher says,"How do you do!"

可以使用如下代码:

      cout<<"The teacher says,\"How do you do!\"\n";

最后两个转义字符\ddd和\xhh是ASCII码的专用表示方法。\ddd是一个以八进制数表示的字符,例如'\101'代表八进制数101的ASCII码所对应的字符,即大写字母'A';'\012'代表八进制数12的ASCII码所对应的字符“换行”符。\xhh是一个以十六进制数表示的ASCII字符,如'\x41'代表十六进制数41的ASCII字符,也是大写字母'A'。用表中的方法可以表示任何可显示的字母字符、数字字符、专用字符、图形字符和控制字符。

【例1-2】某企业从事A,B,C三种产品的生产,该企业各产品的销售额见表1.3,编写程序输出企业的销售数据。

表1.3 企业各产品销售额

问题分析

转义字符可以实现输出格式,转义字符\n实现换行和空行,转义字符\t实现不同行数据列对齐。

编写程序

运行结果

      该企业各产品的销售额:

      产品  销售额
      A         800
      B         1000
      C         1200
5.字符串常量

字符串常量是由一组双引号括起来的0个或多个字符组成的序列。例如:"This is a string","benefit","$12.5"等都是合法的字符串常量,注意不能错写成'C program','benefit','$12.5'。双引号是定界符,不是字符串的一部分,正如单引号标识着一个字符一样。

字符串是用字符型一维数组来存放的,字符型一维数组由连续存储单元组成,每个字符占用一个存储单元,如图1.1所示。系统在每个字符串的末尾自动加上一个字符'\0'作为字符串结束标志,'\0'在这里占用存储空间但不计入字符串的实际长度,该字符的存在意味着数组的单元数必须至少比要存储的字符数多1。两个连续的双引号""也是一个字符串常量,称为空串,占一个字节,该字节用来存放'\0'。

图1.1 字符串在数组中的存储形式

字符串常量与字符常量是不同的。例如,字符常量'c'和字符串常量"c"虽然都只有一个字符,但在内存中的情况是不同的。

'c'在内存中占一个字节,用字符变量来存放,可表示为:

"c"在内存中占两个字节,用字符型一维数组来存放,可表示为:

除了用字符型一维数组存放字符串常量,C++还引入了string类。string类使用起来比数组简单,一般建议使用string类。

6.符号常量

用一个标识符来代表一个常量,称为符号常量。符号常量在使用之前要先定义,定义格式为:

      #define<符号常量名>常量

例如:#define TAXRATE 0.015

其中#define也是一条预处理命令(预处理命令都以“#”开头),称为宏定义命令,当预编绎时,值0.015将会在TAXRATE出现的每个地方替代它。为什么使用符号常量比较好呢?

(1)含义清楚。一个名字比一个数字提供的信息多,看程序时从TAXRATE就可大致知道它代表税率。

(2)容易修改。例如在程序中多处用到税率,一旦税率变动,就需要在程序中作多处修改,若用符号常量TAXRATE代表税率,只需要改变这个符号常量的定义,而不用在程序中查找出这个常量的每个地方并做修改。

为什么TAXRATE要大写呢?当你在程序中间遇到大写的符号名时,你会立即知道这是一个常量而非变量。大写常量只不过是使程序更易阅读的技术之一。如果没有大写常量,程序也会照常工作,但是应该培养大写常量的好习惯。

【例1-3】小王在4S店选中一辆价格为15.8万元的国产汽车,如果车辆购置税税率为10%,他应支付多少车辆购置税?

问题分析

车辆购置税是对在境内购置规定车辆的单位和个人征收的一种税,目前税率为10%,应纳税额的计算公式为:

新车购置税额=购车价格(含税价)/1.17(增值税率17%)×10%

根据上述公式,小王应支付车辆购置税为15.8/1.17∗10%=1.35043万元。

编写程序

运行结果

      汽车单价为:15.8万元
      所需缴纳的车辆购置税为:1.35043万元

使用#define指令易犯的错误:

符号常量定义中没有“=”符号,末尾没有分号。例如:

      #define PRICE=30      //这样定义是错误的

如果这样定义符号常量PRICE,PRICE将会被=30而不是30所代替。

1.4 变量

变量是指在程序运行过程中其值可以随时改变的量,变量可以为任意数据类型。变量代表计算机内存中的某一存储空间,该存储空间中存放的数据就是变量的值。每个变量都有一个名字,这个名字称为变量名。变量名和变量值是两个不同的概念,如图1.2所示,a是变量名,9是变量a的值,即存放在变量a的存储单元中的数据。

图1.2 变量的存储形式

变量提供了一个有名字的内存存储区,可以通过程序对其进行读、写等操作。C++中的每个变量都与一个特定的数据类型相关联,这个类型决定了存储单元的长度(占多少字节)、数据的存储形式、能够存储在该内存区的值的范围以及可以应用其上的操作集。

变量和常量属于某种数据类型。它们的区别在于变量是可寻址的,尽管常量的值也存储在计算机内存中的某个地方,但是我们没有办法访问它们的地址。从变量中取值或赋值,实际上是通过变量名找到相应的存储单元地址,对该存储单元进行读数据操作或写数据操作。

标识符及变量命名规则如下。

在计算机高级语言中,用来标识变量名、符号常量名、函数名、数组名、类型名、文件名的有效字符序列统称为标识符。例如前面用到的符号常量名TAXRATE,PRICE,还有变量名price等都是标识符。

标识符只能由字母、数字和下画线字符3种字符组成,并且必须以字母或下画线开始。例如,abc,f1,p2,_sum等都是合法的标识符,可以作为变量名。标识符是区分大小写的,大写字母和小写字母是不同的,所以标识符stars不同于Stars。在传统的用法中,变量标识符用小写字母,符号常量的标识符用大写字母,以示区别。

下面是不合法的标识符和变量名:

      123,849                //标识符不能以数字开始
      new value,two+three    //标识符组成不能有空格和运算符
      int,if                 //标识符不能用关键字(参见表1.4)

表1.4 关键字表

1.整型变量

1)整型变量的分类

C++语言提供多种整数类型,针对不同用途选择不同的整数类型。具体来讲,C++的各种整数类型的区别在于所提供数值的范围,以及数值是否可以取负值。通过关键字(long,short和unsigned)提供整型(int)的变种,扩展成6种整数类型,具体见表1.5。

表1.5 6种整数类型

C++没有统一规定各类数据在内存中所占的字节数,编译系统分配给int型数据2字节或4字节(由具体的计算机系统和编译器自行决定),Visual C++为每一个int型数据分配4字节。

整数在存储单元中以二进制数字存储。例如整数7的二进制表示为111,在1个字节中存储它需要将前5位置0,将后3位置1,如图1.3所示。

图1.3 使用二进制编码存储整数7

2)整型变量的定义

程序中使用的各种变量都应预先加以定义,即先定义,后使用。

变量声明格式:

      <类型标识符>变量名1[,变量名2,变量名3…];

正确的格式如下:

      int x,y,z;
      unsigned short c,d;
      long e,f;

可以分别声明每个变量,也可以在一条语句中声明多个变量。两种方法效果是一样的,都将为变量赋予名称并安排存储空间。例如上面最后一行的定义也可以等价地写为:

      long e;
      long f;

3)整型变量初始化和赋值

以上变量声明创建了变量但没有为其赋值。如何为变量赋值?

(1)先定义,后赋值。例如:

      int eggs;
      eggs=100;

(2)定义时直接初始化。例如:

      int a=5,b=6,c=7;
      longx=32768;

【例1-4】小王有两个账户,分别有存款100元,现在两个账户分别要支付101元的消费额,为了保证账户正常交易,账户应该定义为什么样的整数类型呢?

问题分析

通常把整数存储为int型,如果数值太大,可以考虑unsigned、long、unsigned long型。

编写程序

运行结果

      转账后余额(int账户)为:-1元
      转账后余额(unsigned账户)为:4294967295元

程序分析

iaccount和101都是int型,所以可以直接进行运算,结果为–1;uaccount和101的数据类型不一致,系统会自动把“较低”的类型提升为“较高”的类型,即101转换为unsigned型,然后进行减运算,运算结果为–1,超越了unsigned型的数据范围,其值将为范围另一端的取值,如图1.4和图1.5所示(当然感兴趣的读者也可以查找二进制补码的知识来解释运算结果)。

图1.4 unsigned型数据范围示意图

图1.5 int型数据范围示意图

4)整数的溢出

如果整数太大,超出了整数类型的范围会怎么样?下面分别将有符号类型和无符号类型整数设置为最大允许值加略大一些的值,看看结果是什么?

【例1-5】整型变量的最大允许值的讨论。

编写程序

运行结果

      2147483647  -2147483648  -2147483647
      4294967295            0            1

程序分析

i和j都是int型,所以可以直接进行运算,表达式i+1超越了int型的数据范围,沿数值增大方向,与INT_MAX(2147483647)相邻的数值即为表达式i+1的值,如图1.5所示,与INT_MAX相隔两个位置的数值即为表达式i+2的值。同样道理,表达式j+1超越了unsigned型的数据范围,如图1.4所示,沿数值增大方向,与UINT_MAX(4294967295)相邻的数值即为表达式j+1的值,与UINT_MAX相隔两个位置的数值即为表达式j+2的值。

2.布尔变量

布尔变量可以赋值为true或false。例如:

      bool found=false;    //定义时直接初始化布尔变量found

当需要一个整数值时,布尔常量被隐式地提升成int型,false变成0,而true变成1。例如:

      int i=true;    //true转变成1,整型变量i的初始值为1

正如常量false和true能自动转换成整数值0和1一样,如果有必要,整数值也能隐式地被转换成布尔类型的值。0被转换成false,非零值都被转换成true。例如:

      bool succeeded=2;    //2转换成true,布尔变量succeeded的初始值为true
3.字符变量

字符变量用于存储字母和标点符号之类的字符,但是在技术实现上字符变量却是整数类型,这是因为字符变量实际存储的并不是字符本身,而是以其代码(一般采用ASCII码)存储的。但是,字符数据在使用上有自己的特点,因此把它单独列出来介绍。

1)字符变量的定义

字符变量用来存储字符常量,即单个字符。字符变量的类型说明符是char,char类型占用一个字节的存储空间。字符变量类型定义的格式和书写规则都与整型变量相同。例如:

      char a,b;    //定义a,b为字符变量

2)字符变量初始化

如果把一个字符常量初始化为字母A,无须记住该字符的ASCII码,使用下面的初始化语句把字符A赋给变量grade:

      char grade='A';

'A'是一个字符常量,其中单引号是必不可少的,编译器遇到'A'时会将其转换为相应的编码值65,系统把整数65赋给变量grade。因为字符实际上以数值的形式存储,所以也可以使用数值编码来赋值:

      char grade=65;

对于ASCII码,这是可以的,但这是一种不好的编程风格。

下面给出了更多字符变量赋值的例子:

      char passed;      //声明一个char变量
      passed= 'Y';    //正确
      passed= Y;         //错误,除非Y是一个已经定义好的char变量
      passed="Y";     //错误,"Y"是一个字符串,无法赋值给char变量

【例1-6】大小写字母的转换。

问题分析

字符变量实际存储的是其相应ASCII码值,所有小写字母的ASCII码值比对应的大写字母的ASCII码值大32,所以通过数值运算可以实现大小写字母的转换。

编写程序

运行结果

      输入字符Y代表Yes
      输入字符N代表No
4.浮点变量

1)浮点变量的分类

在账务和数学计算程序中经常要用到浮点数。浮点数包括float(单精度浮点型),double(双精度浮点型),和long double(长双精度浮点型)类型,浮点数能够表示包括小数在内的更大范围的数,具体见表1.6。

表1.6 3种浮点数类型

不同的计算机系统和编译器对long double型的处理方法不同,Visual C++对long double型和double型一样处理,分配8个字节。

浮点数与整数的最重要的区别是存储方案不同。浮点数表示法将一个数分为小数部分和指数部分并分别存储。例如在十进制中3.14159可表示为0.314159e1,这里0.314159是小数部分,1是指数部分,如图1.6所示。当然,计算机的内部存储实际上使用二进制数字。

图1.6 以浮点格式存储实数3.14159(十进制版本)

2)浮点变量的定义

浮点变量定义的格式和书写规则与整型变量相同。例如:

      float x,y;       //x,y为单精度浮点变量
      double a,b,c;    //a,b,c为双精度浮点变量
5.常变量

在定义变量时,如果加上限定符const,则变量的值在程序运行期间不能改变,这种变量称为常变量。例如:

      const int weight=23;

变量weight被初始化后,其值就被固定了,始终为23,编译器将不允许再修改该变量的值。上面的代码如果改写成下面的形式:

      const int weight;    //常变量的值不确定
      weight=23;           //无法修改常变量的值

如果在声明变量weight时没有提供值,则该变量的值将不确定,并且无法修改。

要区别用限定符const定义的常变量和用#define指令定义的符号常量。用#define定义符号常量是C++语言所采用的方法,但使用const的方法有很多的优越性。通常#define指令经常被认为好像不是语言本身的一部分。例如:

      #define TAXRATE 0.015

当预编译时,所有的符号常量TAXRATE替换为指定值0.015,于是TAXRATE不会加入符号列表中。如果涉及这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是0.015,而不是TAXRATE,甚至要花时间才能找出错误代码的位置。使用const定义变量,就可以有效地解决上面的问题。另外,使用const定义变量可以显式指明数据类型。更重要的是,const方法可以方便地应用于复杂的派生类型。

【例1-7】小王在银行存入3年期存款100万元,若3年期定期存款年利率为4%,利息所得税率为20%,利用单利法计算小王存满3年的实得利息额。

问题分析

单利(simple interest)是指按照固定的本金计算的利息,是计算利息的一种方法。单利法的计算公式为:

实得利息=本金×利率×计息期数×(1–税率)

其中计息期数通常以年为单位。根据上述公式,小王存满3年的实得利息额=100×4%×3×(1–20%)=9.6万元。

编写程序

运行结果

      存满3年的实得利息额为:9.6万元

1.5 数据类型

所谓数据类型,就是对数据分配存储单元的安排,包括存储单元的长度(占多少字节)以及数据的存储形式。不同的数据类型分配不同的长度和存储形式。

1.类型分类

C++语言允许使用的数据类型见表1.7。C++数据类型可分为基本数据类型、派生类型、空类型三大类。本章详细介绍基本类型,即整数类型和浮点数类型两种。例如:78是整数,而42.100是浮点数。布尔型(bool)、字符型(char)、短整型(short)、整型(int)、长整型(long)放在一起称为整数类型。int关键字提供了整型,另外通过关键字(long、short和unsigned)用于提供整型的变种。char类型用于表示字母以及其他字符(如#、%和∗),char类型也可以表示小的整数。float,double统称为浮点数类型,表示带有小数点的数。在基本类型的基础上创建的派生类型,包括数组类型、结构体类型、共用体类型、枚举类型、函数类型和指针类型,后面的章节会逐一详细介绍。

表1.7 C++数据类型表

【例1-8】某公司投资2000000元生产产品A,年产量为180000件,单位产品的变动成本为32元/件,总固定成本为1080000元。如果公司希望获得25%的年投资回报率,那么该公司产品应该如何定价?

问题分析

单位产品的变动成本=32元/件

单位产品的固定成本=1080000元/180000件=6元/件

单位产品总成本=单位产品的变动成本+单位产品的固定成本=32+6=38元/件

单位产品利润=2000000元×25%/180000件=2.78元/件

单位产品价格=38元+2.78元=40.78元/件

则该企业对该种产品的价格应定为40.78元/件。

编写程序

运行结果

      单位产品的变动成本=32元/件
      单位产品的固定成本=1080000/180000=6元/件
      单位产品的总成本=32+6=38元/件
      单位产品的利润=2000000*0.250000/180000=2.777778元/件
      单位产品的价格=38+2.777778=40.777779元/件
      该企业对该种产品的价格应定为40.777779元/件
2.类型转换

当一个运算符的几个操作数类型不同时,如5+3.14,就需要通过一些规则把它们转换为某种共同的类型,然后再进行运算。一般来说,C++会执行自动类型转换,即把“较低”的类型提升为“较高”的类型,并且保证不丢失信息,例如,在计算表达式f+i时,将整型变量i的值自动转换为浮点型(这里的变量f为浮点型)。

除了自动类型转换,可以利用强制类型转换运算符将一个表达式转换成所需类型。强制类型转换形式有两种:

      (类型名)表达式
      类型名(表达式)

例如:

      (double)a (将a转换成double类型)
      int(x+y) (将x+y的值转换成int型)
      (float)7   (将整数7的值转换成float型)

1.6 运算符和表达式

1.算术运算符和算术表达式

1)基本算术运算符

(1)+(加法运算符,或正号运算符,如3+5、+3)。

(2)–(减法运算符,或负号运算符,如5–1、–4)。

(3)∗(乘法运算符,如3∗5)。

(4)/(除法运算符,如5/3)。

(5)%(模运算符,或称求余运算符,%两侧均应为整型数据,如7%3的值为4)。

说明:整型数的除法运算和浮点数的除法运算有很大的不同。浮点类型的除法运算得出一个浮点数结果,例如,5.0/4的值为1.25;而整数除法运算,截断结果中的小数部分,产生一个整数结果,例如,5/4的值为1。

【例1-9】A公司属于商品流通企业,为增值税一般纳税人,售价中不含增值税,该公司第一季度销售收入为600万元,销售成本为510万元,A公司第一季度的实际毛利率为多少?

问题分析

销售毛利率是毛利占销售净值的百分比,通常称为毛利率,其中毛利是销售净收入与产品成本的差。毛利率是一个衡量盈利能力的指标,毛利率越高则说明企业的盈利能力越高,控制成本的能力越强。销售毛利率计算公式:

销售毛利率=(销售收入–销售成本)/销售收入×100%

根据上述公式,A公司第一季度的实际毛利率为(600–510)/600×100%=15%。

编写程序

运行结果

      请输入销售收入、销售成本:
      600 510
      销售毛利率为:0%

变量revenue、cost定义为int型,表达式(revenue-cost)/revenue进行了整数除法运算,截断结果中的小数部分0.15,产生一个整数结果0,解决的方法很简单,只要将变量revenue、cost定义为float型就可以了。

2)自增、自减运算符

自增自减运算符(++、––)作用是使变量的值加1或减1,例如:

i++;等价于i=i+1;(先引用i值,再使i的值加1)。

++i;等价于i=i+1;(先使i的值加1,再引用i值)。

i––;等价于i=i–1;(先引用i值,再使i的值减1)。

––i;等价于i=i–1;(先使i的值减1,再引用i值)。

表1.8给出两个具体实例:

表1.8 自增运算符程序实例

注意:自增运算符(++)和自减运算符(––)只能用于变量,而不能用于常量或表达式。

(1)常量不能进行自增自减运算。

如:4++,与其等价的表示形式为4=4+1,不符合赋值表达式的要求。特别注意的是在C++语言中数组名和函数名都是常量,故不能进行自增自减运算。

(2)表达式不能进行自增自减运算。

如:(x+y)++,与其等价的表示形式为x+y=x+y+1,不符合赋值表达式的要求。

【例1-10】小王将积蓄的100万元进行投资,每年都能获得4%的回报,投资年限为3年,按复利计算3年后他的资产总值将变为多少?

问题分析

复利是指在每经过一个计息期后,都要将所剩利息加入本金,以计算下期的利息。这样,在每一个计息期,上一个计息期的利息都将成为生息的本金,即以利生利,也就是俗称的“利滚利”。复利的计算公式为:

其中,P=本金;i=利率;n=持有期限。根据复利计算公式,小王3年后的资产总值将变为100×(1+4%)3=112.486万元。

编写程序

运行结果

      请输入本金:100
      投资100万元
      3年后的资产总值为112.486万元

3)算术表达式和算术运算符的优先级

用算术运算符和括号将常量、变量、函数等运算对象连接起来的式子,称为算术表达式。例如,下面是一个合法的算术表达式:

      5+'a'-i*f+d%3

C++语言不仅规定了运算符的优先级,还规定了运算符的结合性。二元运算符+和–具有相同的优先级,它们的优先级比运算符∗、/和%的优先级低,而运算符∗、/和%的优先级又比一元运算符+、–和自增减运算符++、––优先级低,圆括号的优先级最高,运算符优先级次序如表1.9所示。在表达式求值时,先按运算符的优先级别顺序执行,优先级高的运算符先执行。例如,表达式a–b∗c,b的左侧为–,右侧为∗,而∗优先级高于–,因此先对b进行乘法操作。

表1.9 按优先级递减顺序排列的运算符

对于大多数的算术运算符,运算符采用从左到右的结合规则。当运算符优先级一致时,按“运算符结合性”处理。例如,在表达式12/3∗2里,有相同优先级的/和∗运算符共享操作数3,所以,按照从左到右的结合性,先执行/后执行∗,这个表达式将被简化为4∗2,结果为8(如果是从右到左计算,先执行∗后执行/,结果将是2,得到错误的结果)。

2.赋值运算符和赋值表达式

1)赋值运算符

在C++语言里,符号=不表示“相等”,而是一个赋值运算符。下面的语句将值560赋给变量a:

      a=560;

注意,符号=左边是变量名,右边是赋给该变量的值,可以是常量,变量或者任何一个表达式。赋值运算符低于所有算术运算符,运算符的结合性是从右到左。例如:a=b=c=5,首先c得到值5,然后b得到值5,最后a得到值5。

2)复合赋值运算符

在赋值符=之前加上其他运算符,可以构成复合的运算符。例如+=、–=、∗=、/=、%=等。每个这样的赋值运算符在使用时都是左边为变量名,右边为一个表达式。变量被赋予一个新的值,这个新值是它原来的值根据右边表达式的值进行调整得到的。例如:

      s+=20;    //等价于s=s+20;
      t*=3;     //等价于t=t*3;
      a%=5;     //等价于a=a%5;

复合赋值运算符的右边表达式还可以更为复杂,又如:

      x*=5*a+6;    //等价于x=x*(5*a+6);

这些复合赋值运算符具有与=同样低的优先级,也就是说低于所有的算术运算符的优先级,因此在与x进行相乘之前把6加到了5∗a上。

3)赋值表达式

用赋值运算符和括号将常量、变量、函数等运算对象连接起来的式子,称为赋值表达式。它的一般形式为:

      变量赋值运算符表达式

上面的“表达式”可以是常量、变量、函数等运算对象,也可以是各种运算对象连接而成的式子。对赋值表达式求解的过程是:先求赋值运算符右侧的“表达式”的值,然后赋给赋值运算符左侧的变量。最后变量的值就是赋值表达式的值。表1.10给出几个合法的赋值表达式。

表1.10 赋值表达式示例

3.关系运算符和关系表达式

关系运算符主要用作比较两个量的大小、两个量是否相等或者两个量是否不相等。所以关系运算符主要作比较运算。表1.11列出了完整的关系运算符。

表1.11 关系运算符

关系运算符的优先级次序说明:

(1)6个关系运算符中,前4种<、<=、>、>=的优先级相同,后2种==和!=的优先级相同,前4种优先级高于后2种;

(2)关系运算符的优先级低于算术运算符;

(3)关系运算符的优先级高于赋值运算符。

用关系运算符将两个数值或数值表达式连接起来的式子,称关系表达式。如果关系为真,关系表达式的值为布尔常量true;如果为假,关系表达式的值为布尔常量false。当需要一个整数值时,布尔常量被隐式地提升成int型,false变成0,而true变成1。

例如:

5>2为真,则该关系表达式的值为true。

(2+a)==a为假,则该关系表达式的值为false。

【例1-11】用关系表达式描述消费者的预算约束。

问题分析

消费者的选择不仅取决于消费者的偏好,还要受到支付能力和价格的限制。这种在既定价格下,消费者对各种商品和服务的支付能力的限制表现为一种预算约束。经济学认为消费者总是选择他们能够负担的最佳物品。(x1,x2)来表示消费者的消费束,即消费者选择商品x1时的消费量和选择商品x2时的消费量;又知道两种商品的价格(p1,p2)和消费者要花费的货币总数m。则消费者的预算约束可以写为:p1∗x1+p2∗x2<=m。

若某些消费束刚好可以把消费者的收入用完,则这一系列消费束构成值为m的预算线,即:p1∗x1+p2∗x2==m。

【例1-12】假设一个消费者现在拥有10美元的财富,他正在考虑是否要进行一项赌博,在这次赌博中,他赚5美元的概率是50%,输5美元的概率也是50%。即他的期望收益是10美元,则他的期望效用如何用关系表达式描述?

问题分析

期望效用指的是消费者在不确定条件下可能获得的各种结果的效用的加权平均数。期望效用越大意味着这个结果发生的概率越大,它用于判断不同人对风险的不同的偏好。

对于一个风险厌恶的消费者而言,财富的期望效用大于财富的期望值的效用0.5u(5)+0.5u(15)>u(10)。

【例1-13】项目A第一年年初投资10万元,从第一年年末连续两年有5.6万元的回报,设折现率为8%,计算该项目的净现值,并判断企业是否会进行此项投资。

问题分析

净现值是一项投资所产生的未来现金流的折现值与项目投资成本之间的差值。净现值法是评价投资方案的一种方法。该方法是利用净现金效益量的总现值与净现金投资量算出净现值,然后根据净现值的大小来评价投资方案。净现值的计算公式为:

其中,NPV为净现值,C0为初始投资额,Ct为t年现金流量,r为折现率,n为投资项目的周期,针对每个方案计算净现值,有下面决策标准:

净现值≥0投资方案可行;

净现值<0投资方案不可行;

净现值均>0净现值最大的方案为最优方案。根据公式,本题净现值为万元,所以企业不会进行此项投资。

编写程序

运行结果

      请输入初始投资额、年收益:10 5.6
      净现值为-0.013 717 7小于等于0,投资方案不可行
4.逻辑运算符和逻辑表达式

在实际应用中,两个或多个关系表达式组合起来更为有用,这时候就要借助逻辑运算符连接式子。有三个逻辑运算符:与(&&),或(||),非(!)。

逻辑运算符的优先级次序说明:

(1)!优先级高于&&,&&优先级高于||。

(2)!优先级高于基本算术运算符,&&和||低于关系运算符。

逻辑运算符的含义:

与运算&&,参与运算的两个量都为真时,结果才为真,否则为假。例如:5>0&&4>2,由于5>0为真,4>2也为真,相与的结果也为真。

或运算||,参与运算的两个量只要有一个为真,结果就为真。两个量都为假时,结果为假。例如:5>0||5>8,由于5>0为真,相或的结果也就为真。

非运算!,参与运算量为真时,结果为假;参与运算量为假时,结果为真。例如:!(4>7),由于4>7为假,所以非运算的结果为真。

注意:逻辑表达式是从左到右求值的,在知道结果值为真或假后立即停止计算。例如:x!=0&&(20/x)<5,当x=0时,此时已经能判断表达式为假,不必再进行(20/x)<5的运算;只有当x不为0时,才计算第二个表达式的值。

【例1-14】客户申请贷款,必须满足以下条件,资产不低于10万,或开户年限不小于10年,并且没有过欠款记录,试用表达式描述客户申请贷款的条件。

问题分析

令a表示资产,n表示开户年限,年总存款额为x;t表示欠款次数,t=0表示无不良记录,当出现欠款行为时执行t++;客户申请贷款的条件可表示为(a>=10||n>=10)&&!t。

【例1-15】关键审计合伙人在审计客户成为公共利益实体后的任职时间有如下规定,试用表达式描述下面几种情况:

(1)在审计客户成为公众利益实体前,如果关键审计合伙人已为该客户服务的时间“不超过3年”,在该客户成为公众利益实体后,该合伙人还可以为该客户提供服务的年限为“5年减去已经服务的年限”;

(2)如果关键审计合伙人为客户服务了“4年或更长的时间”,在该客户成为公众利益实体后,该合伙人还可以继续服务两年;

(3)如果审计客户是“首次公开发行证券的公司”,关键审计合伙人在该公司上市后连续提供服务的期限不得超过两个完整的会计年度。

问题分析

若ipo表示客户是否为“首次公开发行证券的公司”,ipo取值为1表示是“首次公开发行证券的公司”,否则ipo取值为0;t表示关键审计合伙人已经提供服务的期限,n表示客户成为公共利益实体后合伙人可以服务的时间。具体描述如表1.12所示。

表1.12

5.条件运算符和条件表达式

当a>b时将a的值赋给max,否则将b的值赋给max。无论a>b条件是否满足,都是给同一个变量赋值。条件运算符提供了一种便利的表示方法,处理这类问题。例如可以用下面的语句实现:

      max=(a>b)?a:b;

赋值号右侧的(a>b)?a:b是一个条件表达式,“?:”是一个条件运算符。

条件运算符由两个符号(?和:)组成,必须一起使用,要求有三个操作对象,称为三目(元)运算符。条件运算符优先级高于赋值运算符,低于其他运算符。采用这种条件表达式可以编写出很简洁的代码。图1.7给出了条件表达式的逻辑框图。

图1.7 条件表达式逻辑框图

条件表达式的一般形式为:

      表达式1?表达式2:表达式3

可以这样理解条件表达式,首先计算表达式1,如果其值不等于0(为真),则计算表达式2的值,并以该值作为条件表达式的值,否则计算表达式3的值,并以该值作为条件表达式的值。表达式2与表达式3中只能有一个表达式被计算。

【例1-16】中国财政部数据显示,中国7月全国财政收入约12700亿元,中国7月全国财政支出约10300亿元,试用条件运算符描述中国7月财政状况,判断财政盈余还是财政赤字,并编程实现。

问题分析

政府在每一财政年度开始之初,总会制定一个当年的财政预算方案,若实际执行结果收入大于支出,为财政盈余,支出大于收入的经济现象,就叫作财政赤字。理论上说,财政收支平衡是财政的最佳情况,在现实中就是财政收支相抵或略有结余。

设revenue代表财政收入,expend代表财政支出,用条件运算符可以表示如下:

      (expend>revenue)?"财政赤字":"财政盈余"

编写程序

运行结果

      财政盈余2400亿元
6.逗号运算符和逗号表达式

C++语言提供一种特殊的运算符——逗号运算符。用逗号运算符将两个表达式连接起来,称为逗号表达式。例如:

      3*2,5+6

逗号表达式的一般形式为:

      表达式1,表达式2,…,表达式n

逗号表达式的值运算过程:从左向右,依次对表达式求值,先计算表达式1的值,再计算表达式2的值,……,最后得到表达式n的值就是逗号表达式的值,所以表达式“3∗2,5+6”的值为11。

注意:逗号运算符是所有运算符中级别最低的。逗号表达式保证左边子表达式在计算右边的子表达式之前生效。例如:

      x=(y=3,(z=++y+2)+5);

首先把y赋值为3,然后y自增后值为4,执行4加上2,把结果6赋值给z,接下来把z加5,最后把x赋值为结果值11。

7.运算符优先级与求值次序

表1.13总结了所有运算符的优先级与结合性,其中的一些规则我们还没有讲述。同一行中的各运算符具有相同的优先级,各行间从上往下优先级逐行降低。例如,∗、/与%三者具有相同的优先级,它们的优先级都比二元运算符+、–高。运算符–>和.用于访问结构成员。

表1.13 运算符的优先级与结合性

本章小结

本章首先给读者展示了一个用C++语言实现简单计算机程序,然后着重介绍了C++语言编程的基础组成成分,包括数据类型、运算符和表达式等。

在C++语言中,数据类型可分为基本数据类型、派生类型和空类型三大类。在本章中,我们详细介绍了基本数据类型。其余类型在后面各章中陆续介绍。

对于基本数据类型量,按其取值是否可改变又分为常量和变量两种。在程序执行过程中,其值不发生改变的量称为常量,其值可变的量称为变量。它们可与数据类型结合起来分类。例如,可分为整型常量、整型变量、浮点常量、浮点变量、布尔常量、布尔变量、字符常量、字符变量、字符串常量、符号常量和常变量。在程序中,常量是可以不经说明而直接引用的,而变量则必须先定义后使用。

在不同类型数据的混合运算中,C++会自动实现类型转换,由少字节类型向多字节类型转换。不同类型的量相互赋值时也由系统自动进行转换,把赋值号右边的类型转换为左边的类型。除了自动类型转换,C++还可以利用强制类型转换运算符进行类型转换。

C++语言中运算符和表达式数量之多,在高级语言中是少见的。正是丰富的运算符和表达式使C++语言功能十分完善。这也是C++语言的主要特点之一。

C++语言的运算符不仅具有不同的优先级,而且还有一个特点,就是它的结合性。在表达式中,各运算量参与运算的先后顺序不仅要遵守运算符优先级别的规定,还要受运算符结合性的制约,以便确定是自左向右进行运算还是自右向左进行运算。这种结合性是其他高级语言的运算符所没有的,因此也增加了C++语言的复杂性。

一般而言,单目运算符优先级较高,赋值运算符优先级低。算术运算符优先级较高,关系和逻辑运算符优先级较低。多数运算符具有左结合性,单目运算符、三目运算符、赋值运算符具有右结合性。

表达式则是由运算符连接常量、变量、函数所组成的式子。每个表达式都有一个值和类型。表达式求值按运算符的优先级和结合性所规定的顺序进行。

思考题

1. 已知复利终值的计算公式为F=P(1+i)^n,请写出只含加法、乘法的三年期复利终值表达式。

2. 生产企业出口货物劳务免抵退税的计算公式如下,请设定变量,用算术表达式实现以下公式:

当期应纳税额=当期销项税额–(当期进项税额–当期不得免征和抵扣税额)

当期不得免征和抵扣税额=当期出口货物离岸价×外汇人民币折合率×(出口货物适用税率–出口货物退税率)–当期不得免征和抵扣税额抵减额

当期不得免征和抵扣税额抵减额=当期免税购进原材料价格×(出口货物征税率–出口货物退税率)

练习题

1. 已知A公司4月份购买甲产品支付货款10000元,增值税进项税额1700元,取得增值税专用发票。销售甲产品含税销售额为23400元。请设计变量,编写一个程序,求出增值税额。

增值税额计算公式如下:

应纳税额=当期销项税额–当期进项税额

销项税额=销售额×税率

销售额=含税销售额÷(1+税率)

2. 公司固定资产原值为11万元,预计残值为1万元,使用年限为4年。利用年数总和法,编程计算每一年的固定资产折旧额。

年折旧额计算公式如下: