0%

C++ Primer personal answer chapter02

《C++ Primer》第五版习题个人答案

练习2.1

类型 int、long、long long 和 short 的区别是什么?无符号类型和带符号类型的区别是什么?float 和 double的区别是什么?

int、long、long long和short是整数类型,它们的区别在于占用的存储空间和取值范围的大小。以下是各个类型的最小尺寸:shortint 至少16位,long 至少32位,long long 至少64位。
floatdouble是浮点数类型,区别在于精度和取值范围的大小。float是单精度浮点数类型,通常占用4个字节(32位)的存储空间。double是双精度浮点数类型,通常占用8个字节(64位)的存储空间。

练习2.2

计算按揭贷款时,对于利率、本金和付款分别应选择何种数据类型?说明你的理由。

利率:利率通常是一个小数,例如3.5%可以表示为0.035。在计算利息时,我们需要进行乘法和除法运算,因此选择浮点数类型更合适。可以选择使用floatdouble类型来表示利率,具体选择哪种类型取决于所需的精度和范围;
本金:本金是贷款的原始金额,通常是一个整数或浮点数。在计算本金时,我们通常只需要进行加法和减法运算,因此选择整数类型或浮点数类型都可以。如果贷款金额较大,可以选择使用long longdouble类型;
付款:付款是按揭贷款的每期还款金额,通常是一个固定的数值。付款金额可以是整数或浮点数,取决于贷款的具体情况。

练习2.3

读程序写结果。

1
2
3
4
5
6
7
8
unsigned u = 10, u2 = 42;
std::cout << u2 - u << std::endl;
std::cout << u - u2 << std::endl;
int i = 10, i2 = 42;
std::cout << i2 - i << std::endl;
std::cout << i - i2 << std::endl;
std::cout << i - u << std::endl;
std::cout << u - i << std::endl;

输出:

1
2
3
4
5
6
32
4294967264
32
-32
0
0

练习2.4

编写程序检查你的估计是否正确,如果不正确,请仔细研读本节直到弄明白问题所在。

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>
int main()
{
unsigned u = 10, u2 = 42;
std::cout << u2 - u << std::endl;
std::cout << u - u2 << std::endl;
int i = 10, i2 = 42;
std::cout << i2 - i << std::endl;
std::cout << i - i2 << std::endl;
std::cout << i - u << std::endl;
std::cout << u - i << std::endl;
}

exercise2.4

练习2.5

指出下述字面值的数据类型并说明每一组内几种字面值的区别:

  • (a) ‘a’, L’a’, “a”, L”a”
  • (b) 10, 10u, 10L, 10uL, 012, 0xC
  • (c) 3.14, 3.14f, 3.14L
  • (d) 10, 10u, 10., 10e-2

(a): 字符字面值,类型为char;宽字符字面值,类型为wchar_t;字符串字面值,类型为const char[];宽字符串字面值,类型为const wchar_t[]

(b): 整型字面值,默认为int类型;无符号整型字面值,类型为unsigned int;长整型字面值,类型为long;无符号长整型字面值,类型为unsigned long;八进制整型字面值,类型为int;十六进制整型字面值,类型为int

(c): 浮点型字面值,默认为double类型; 单精度浮点型字面值,类型为float;长双精度浮点型字面值,类型为long double

(d): 整型字面值,默认为 int类型;无符号整型字面值,类型为unsigned int;浮点型字面值,默认为double类型;科学计数法表示的浮点型字面值,默认为double类型。

练习2.6

下面两组定义是否有区别,如果有,请叙述之:

1
2
int month = 9, day = 7;
int month = 09, day = 07;

第一行定义的是十进制整型。
以0为开头的整数常量被解释为八进制数,但是八进制只包含数字0到7,所以09是非法的八进制数。

练习2.7

下述字面值表示何种含义?它们各自的数据类型是什么?

  • (a) “Who goes with F\145rgus?\012”
  • (b) 3.14e1L
  • (c) 1024f
  • (d) 3.14L

(a): Who goes with Fergus?(换行),string 类型

(b): long double

(c): 非法,整型后不可加f

(d): long double

练习2.8

请利用转义序列编写一段程序,要求先输出 2M,然后转到新一行。修改程序使其先输出 2,然后输出制表符,再输出 M,最后转到新一行。

1
2
3
4
5
6
7
#include<iostream>
int main()
{
std::cout<<"2\115\n";
std::cout<<"2\t\115\n";
return 0;
}

练习2.9

解释下列定义的含义,对于非法的定义,请说明错在何处并将其改正。

  • (a) std::cin >> int input_value;
  • (b) int i = { 3.14 };
  • (c) double salary = wage = 9999.99;
  • (d) int i = 3.14;

(a):非法,std::cin是输入流对象,>>运算符用于读取数据并存储到变量中,不能将变量直接输入,应该先初始化。

1
2
int input_value = 0;
std::cin >> input_value;

(b): 合法,但会导致精度丢失。用列表初始化内置类型的变量时,如果存在丢失信息的风险,则编译器将报错。

1
double i = { 3.14 };

(c): 非法,不能将未定义变量wage的值赋给变量salary

1
2
double wage = 9999.99;
double salary = wage;

(d): 合法,但会导致精度丢失。

1
double i = 3.14;

练习2.10

下列变量的初值分别是什么?

1
2
3
4
5
6
7
std::string global_str;
int global_int;
int main()
{
int local_int;
std::string local_str;
}

在C++中,全局变量和静态变量会被默认初始化为它们的零值,而局部变量(包括函数内部定义的变量)不会被默认初始化,它们的值是未定义的。
global_int 作为全局变量的int类型,所以初值为 0 。
local_int 是局部变量并且没有初始化,它的初值是未定义的(作用域仅限于main()内部)。
global_strlocal_str 作为全局变量的std::string类型,该对象定义了默认的初始化方式,即初始化为空字符串。

练习2.11

指出下面的语句是声明还是定义:

  • (a) extern int ix = 1024;
  • (b) int iy;
  • (c) extern int iz;
1
2
3
(a): 定义
(b): 声明并定义
(c): 声明

练习2.12

请指出下面的名字中哪些是非法的?

  • (a) int double = 3.14;
  • (b) int _;
  • (c) int catch-22;
  • (d) int 1_or_2 = 1;
  • (e) double Double = 3.14;

(a) double 是C++中的关键字,不能用作变量名。 (c)变量名中不能包含连字符(减号),只能使用字母、数字和下划线。 (d) 变量名不能以数字开头。
其他合法。

练习2.13

下面程序中 j 的值是多少?

1
2
3
4
5
6
int i = 42;
int main()
{
int i = 100;
int j = i;
}

100

练习2.14

下面的程序合法吗?如果合法,它将输出什么?

1
2
3
4
int i = 100, sum = 0;
for (int i = 0; i != 10; ++i)
sum += i;
std::cout << i << " " << sum << std::endl;

合法。最后i为全局变量输出,for循环为一到九相加,输出是 100 45

练习2.15

下面的哪个定义是不合法的?为什么?

  • (a) int ival = 1.01;
  • (b) int &rval1 = 1.01;
  • (c) int &rval2 = ival;
  • (d) int &rval3;

(b)(d) 不合法,(b) 引用类型必须绑定到一个对象上,而不能绑定到字面值上。字面值 1.01 是一个临时值,无法被引用。(d) 引用类型在定义时必须初始化,必须绑定到一个对象。

练习2.16

考察下面的所有赋值然后回答:哪些赋值是不合法的?为什么?哪些赋值是合法的?它们执行了哪些操作?

1
2
3
4
5
int i = 0, &r1 = i; double d = 0, &r2 = d;
- (a) r2 = 3.14159;
- (b) r2 = r1;
- (c) i = r2;
- (d) r1 = d;
1
2
3
4
(a): 合法。给 d 赋值为 3.14159。
(b): 合法。会执行自动转换(int->double)。
(c): 合法。会发生小数截取。
(d): 合法。会发生小数截取。

练习2.17

执行下面的代码段将输出什么结果?

1
2
3
int i, &ri = i;
i = 5; ri = 10;
std::cout << i << " " << ri << std::endl;

输出:

1
10, 10

由于 rii 的引用,将 ri 的值设置为 10 实际上就是将 i 的值设置为 10。
由于 iri 引用同一个对象,它们的值都是 10。

练习2.18

编写代码分别改变指针的值以及指针所指对象的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
int main()
{
int i = 42;
int *ptr = &i; // ptr指向i的地址

int j = 10;
ptr = &j; // 更改ptr的值,使其指向j的地址

*ptr = 21; // 修改ptr所指对象的值为21,即修改j的值为21

std::cout << *ptr << std::endl; // 输出21
std::cout << j << std::endl; // 输出21

return 0;
}

练习2.19

说明指针和引用的主要区别

  1. 引用是另一个对象的别名本身并非一个对象,而指针本身就是一个对象。
  2. 引用必须初始化,并且一旦定义了引用就无法再绑定到其他另外的对象,之后每次引用都是访问它最初绑定的那个对象。而指针无须在定义时赋初值,也可以重新赋值让其指向其他对象。

练习2.20

请叙述下面这段代码的作用。

1
2
3
int i = 42;
int *p1 = &i;
*p1 = *p1 * *p1;

让指针 pi 指向 i,然后将 i 的值重新赋值为 42 * 42 (1764)。

练习2.21

请解释下述定义。在这些定义中有非法的吗?如果有,为什么?

1
2
3
4
int i = 0;
(a) double* dp = &i;
(b) int *ip = i;
(c) int *p = &i;
1
2
3
(a): 非法。int型对象不能赋给double型指针 。
(b): 非法。不能直接将 `int` 变量赋给指针。
(c): 合法。

练习2.22

假设 p 是一个 int 型指针,请说明下述代码的含义。

1
2
if (p) // ...
if (*p) // ...

if (p) // ... 这个条件语句检查指针 p是否为非空指针。如果 p的值不为零(即指针指向一个有效的内存地址),条件为真,执行 if 语句块中的代码。如果 p 的值为零(即指针为空指针),条件为假,跳过 if 语句块中的代码。
if (*p) // ... 这个条件语句检查指针 p 所指的对象的值是否为非零。通过解引用指针 p,可以访问指针所指的对象。如果解引用后的值不为零,条件为真,执行 if 语句块中的代码。如果解引用后的值为零,条件为假,跳过 if 语句块中的代码。

练习2.23

给定指针 p,你能知道它是否指向了一个合法的对象吗?如果能,叙述判断的思路;如果不能,也请说明原因。

不能。只有在运行时,通过访问指针 p 所指的内存地址,才能确定它是否指向了一个合法的对象。
在C++中,指针的合法性是一个相对的概念。一个指针被认为是合法的,如果它指向了一个已分配的内存块,或者指向了一个有效的对象。然而,即使指针指向了一个已分配的内存块,也不能保证该内存块包含了一个有效的对象。

练习2.24

在下面这段代码中为什么 p 合法而 lp 非法?

1
2
3
int i = 42;
void *p = &i;
long *lp = &i;

void * 可以指向任何类型的对象。long指针类型与int对象不匹配。

练习2.25

说明下列变量的类型和值。

  • (a) int* ip, i, &r = i;
  • (b) int i, *ip = 0;
  • (c) int* ip, ip2;
1
2
3
(a): ip 是一个int指针, i 是int类型, r 是 i 的引用。
(b): i 是int类型, ip 是空指针。
(c): ip 是一个int的指针, ip2 是int类型。

练习2.26

下面哪些语句是合法的?如果不合法,请说明为什么?

1
2
3
4
const int buf;      
int cnt = 0;
const int sz = cnt;
++cnt; ++sz;

(a):不合法,const 对象必须初始化。
(b):合法。
(c):合法。
(d):不合法, const 对象不能被改变。

练习2.27

下面的哪些初始化是合法的?请说明原因。

1
2
3
4
5
6
7
(a) int i = -1, &r = 0;         
(b) int *const p2 = &i2;
(c) const int i = -1, &r = 0;
(d) const int *const p3 = &i2;
(e) const int *p1 = &i2;
(f) const int &const r2;
(g) const int i2 = i, &r = i;

(a)不合法,因为 &r 是一个引用,引用必须绑定到一个对象上,而不能绑定到一个字面值上。
(f)不合法,因为引用本身就是一个常量,不需要额外的 const 修饰符。
(b), (c), (d), (e), (g) 这些初始化是合法的。

练习2.28

说明下面的这些定义是什么意思,挑出其中不合法的。

1
2
3
4
5
(a) int i, *const cp;       
(b) int *p1, *const p2;
(c) const int ic, &r = ic;
(d) const int *const p3;
(e) const int *p;

(a)(b)(d)中的常量指针都没有初始化,是不合法的;(c)中引用变量r需要初始化;(e)是合法的。在定义指针变量时,如果没有提供初始值,指针变量会被默认初始化为 nullptr,表示它当前不指向任何有效的内存地址。

练习2.29

假设已有上一个练习中定义的那些变量,则下面的哪些语句是合法的?请说明原因。

1
2
3
4
5
6
(a) i = ic;     
(b) p1 = p3;
(c) p1 = &ic;
(d) p3 = &ic;
(e) p2 = p1;
(f) ic = *p3;

(a)合法;(b)不合法,不能将指向常量的指针赋值给非常量指针,因为这可能导致通过非常量指针修改常量的值;(c)合法,非常量指针可以指向常量对象,但不能通过该指针修改常量对象的值;(d)不合法,不能改变常量指针的指向;(e)不合法,常量指针指针一旦被初始化,就不能再改变它所指向的地址;(f)不合法,不能修改常量的值。

练习2.30

对于下面的这些语句,请说明对象被声明成了顶层const还是底层const?

1
2
3
const int v2 = 0; int v1 = v2;
int *p1 = &v1, &r1 = v1;
const int *p2 = &v2, *const p3 = &i, &r2 = v2;

v2 是顶层const;v1 没有被声明为const,它是一个非常量;p1 和 r1 都没有被声明为const,它们是非常量指针;p2 是底层const;p3 既是顶层const又是底层const(靠右的const是顶层const,靠左的是底层const);r2 是底层const。

练习2.31

假设已有上一个练习中所做的那些声明,则下面的哪些语句是合法的?请说明顶层const和底层const在每个例子中有何体现。

1
2
3
4
5
r1 = v2; // 合法, 顶层const在拷贝时不受影响
p1 = p2; // 不合法, p2 是底层const,如果要拷贝必须要求 p1 也是底层const
p2 = p1; // 合法, int* 可以转换成const int*
p1 = p3; // 不合法, p3 是一个底层const,p1 是非常量指针
p2 = p3; // 合法, p2 和 p3 都是底层const,拷贝时忽略掉顶层const

练习2.32

下面的代码是否合法?如果非法,请设法将其修改正确。

1
int null = 0, *p = null;

非法,将一个整数值直接赋给指针是不允许的。

1
int null = 0, *p = &null;

练习2.33

利用本节定义的变量,判断下列语句的运行结果。

1
2
3
4
5
6
a=42; // 合法
b=42; // 合法
c=42; // 合法
d=42; // d 是一个 int *,所以语句非法,指针指向地址
e=42; // e 是一个 const int *, 所以语句非法
g=42; // 可以为常量引用绑定字面值,但是g 是一个 const int 的引用,引用都是底层const,所以不能被赋值

练习2.34

基于上一个练习中的变量和语句编写一段程序,输出赋值前后变量的内容,你刚才的推断正确吗?如果不对,请反复研读本节的示例直到你明白错在何处为止。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<iostream>
int main()
{
int i=0,&r=i;
auto a=r;
const int ci=i,&cr=ci;
auto b=ci;
auto c=cr;
auto d=&i;
auto e=&ci;
auto &g=ci;
a=42,b=42,c=42;
d=42,e=42,g=42;
return 0;
}

报错
exercise2.34

练习2.35

判断下列定义推断出的类型是什么,然后编写程序进行验证。

1
2
3
const int i = 42;
auto j = i; const auto &k = i; auto *p = &i;
const auto j2 = i, &k2 = i;

j:int,k:const int的引用,p:const int *,j2:const int,k2:const int 的引用。

练习2.36

关于下面的代码,请指出每一个变量的类型以及程序结束时它们各自的值。

1
2
3
4
5
int a = 3, b = 4;
decltype(a) c = a;
decltype((b)) d = a;
++c;
++d;

a,b,c 是 int;d是int &;程序结束时,a=4,b=4,c=4,d=4。(d 引用的是 a,所以 a 的值增加 1,变为 4
d 的值也是 4,因为它是 a 的引用)

练习2.37

赋值是会产生引用的一类典型表达式,引用的类型就是左值的类型。也就是说,如果 i 是 int,则表达式 i=x 的类型是 int&。根据这一特点,请指出下面的代码中每一个变量的类型和值。

1
2
3
int a = 3, b = 4;
decltype(a) c = a;
decltype(a = b) d = a;

a,b,c是int,d是int&;a=3,b=4,c=3,d=3。

练习2.38

说明由decltype 指定类型和由auto指定类型有何区别。请举一个例子,decltype指定的类型与auto指定的类型一样;再举一个例子,decltype指定的类型与auto指定的类型不一样。

decltype 推导出的类型可以是表达式的类型,而 auto 推导出的类型必须是初始化表达式的类型
decltype 处理顶层const和引用的方式与 auto不同,decltype会将顶层const和引用保留起来。
指定类型一样的情况:

1
2
3
int x = 1;
decltype(x) y = x; // y 的类型为 int,与 auto 推导出的类型相同
auto z = x; // z 的类型为 int,与 decltype 推导出的类型相同

指定类型不一样的情况:

1
2
3
const int x = 1;
decltype(x) y = x; // y 的类型为 const int,decltype 保留了顶层 const
auto z = x; // z 的类型为 int,auto 去掉了顶层 const

练习2.39

编译下面的程序观察其运行结果,注意,如果忘记写类定义体后面的分号会发生什么情况?记录下相关的信息,以后可能会有用。

1
2
3
4
5
struct Foo { /* 此处为空  */ } // 注意:没有分号
int main()
{
return 0;
}

exercise2.39

练习2.40

根据自己的理解写出 Sales_data 类,最好与书中的例子有所区别。

1
2
3
4
5
6
7
8
9
struct Sale_data
{
std::string bookNo;
std::string bookName;
unsigned units_sold = 0;
double revenue = 0.0;
double price = 0.0;
//...
}

练习2.41

使用你自己的Sale_data类重写1.5.1节(第20页)、1.5.2节(第21页)和1.6节(第22页)的练习。眼下先把Sales_data类的定义和main函数放在一个文件里。

1.5.1

以下程序用于计算两个相同IBSN的Sales_data对象,输出他们的和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<iostream>
#include<string>
struct Sales_data
{
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
double price = 0.0;

};

int main()
{
Sales_data data1,data2;
double price=0;
std::cin>>data1.bookNo>>data1.units_sold>>price;
data1.revenue=data1.units_sold*price;
std::cin>>data2.bookNo>>data2.units_sold>>price;
data2.revenue=data2.units_sold*price;

if (data1.bookNo==data2.bookNo)
{
unsigned totalCnt=data1.units_sold+data2.units_sold;
double totalRevenue=data1.revenue+data2.revenue;
std::cout<<data1.bookNo<<" "<<totalCnt<<" "<<totalRevenue<<" ";
return 0;
}
else
{
std::cerr<<"Data must refer to the same ISBN"<<std::endl;
return -1;
}
return 0;
}

1.5.2

和上一问程序相同,代码实现了输入多条销售记录并统计每个ISBN(每本书)有几条记录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<iostream>
#include<string>
struct Sales_data
{
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
double price = 0.0;

};

int main()
{
Sales_data data1,data2;
double price=0;
std::cin>>data1.bookNo>>data1.units_sold>>price;
data1.revenue=data1.units_sold*price;
std::cin>>data2.bookNo>>data2.units_sold>>price;
data2.revenue=data2.units_sold*price;

if (data1.bookNo==data2.bookNo)
{
unsigned totalCnt=data1.units_sold+data2.units_sold;
double totalRevenue=data1.revenue+data2.revenue;
std::cout<<data1.bookNo<<" "<<totalCnt<<" "<<totalRevenue<<" ";
return 0;
}
else
{
std::cerr<<"Data must refer to the same ISBN"<<std::endl;
return -1;
}
return 0;
}

1.6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <string>

struct Sales_data
{
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
double price = 0.0;

};

int main()
{
Sales_data total;
double totalprice=0;
if (std::cin >> total.bookNo>>total.units_sold>>totalprice)
{
total.revenue=total.units_sold*totalprice;
Sales_data trans;
double transprice;
while (std::cin>>trans.bookNo>>trans.units_sold>>transprice)
{
if (trans.bookNo==total.bookNo)
{
total.units_sold +=trans.units_sold;
total.revenue +=trans.revenue;
}
else
{
std::cout<<total.bookNo<<" "<<total.units_sold<<" "<<total.revenue<<" ";
if (total.units_sold!=0)
{
std::cout<<total.revenue/total.units_sold<<std::endl;
}
else
{
std::cout<<"(No Sales)"<<std::endl;
}
total.bookNo=trans.bookNo;
total.units_sold=trans.units_sold;
total.revenue=trans.revenue;
}

}

std::cout<<total.bookNo<<" "<<total.units_sold<<" "<<total.revenue<<" ";
if (total.units_sold!=0)
{
std::cout<<total.revenue/total.units_sold<<std::endl;
}
else
{
std::cout<<"(No Sales)"<<std::endl;
}
return 0;
}
else
{
std::cerr<<"No Data?!"<<std::endl;
return -1;
}

}

练习2.42

根据你自己的理解重写一个Sales_data.h头文件,并以此为基础重做2.6.2节(第67页)的练习。

ex2_42.h

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef Sales_data_h
#define Sales_data_h
#include<string>
struct Sales_data
{
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
double price = 0.0;

};
#endif

1.5.1&1.5.2(将结构体用头文件替换即可)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<iostream>
#include<string>
#include"ex2_42.h"

int main()
{
Sales_data data1,data2;
double price=0;
std::cin>>data1.bookNo>>data1.units_sold>>price;
data1.revenue=data1.units_sold*price;
std::cin>>data2.bookNo>>data2.units_sold>>price;
data2.revenue=data2.units_sold*price;

if (data1.bookNo==data2.bookNo)
{
unsigned totalCnt=data1.units_sold+data2.units_sold;
double totalRevenue=data1.revenue+data2.revenue;
std::cout<<data1.bookNo<<" "<<totalCnt<<" "<<totalRevenue<<" ";
return 0;
}
else
{
std::cerr<<"Data must refer to the same ISBN"<<std::endl;
return -1;
}
return 0;
}

1.6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<iostream>
#include<string>
#include"ex2_42.h"

int main()
{
Sales_data total;
double totalprice=0;
if (std::cin >> total.bookNo>>total.units_sold>>totalprice)
{
total.revenue=total.units_sold*totalprice;
Sales_data trans;
double transprice;
while (std::cin>>trans.bookNo>>trans.units_sold>>transprice)
{
if (trans.bookNo==total.bookNo)
{
total.units_sold +=trans.units_sold;
total.revenue +=trans.revenue;
}
else
{
std::cout<<total.bookNo<<" "<<total.units_sold<<" "<<total.revenue<<" ";
if (total.units_sold!=0)
{
std::cout<<total.revenue/total.units_sold<<std::endl;
}
else
{
std::cout<<"(No Sales)"<<std::endl;
}
total.bookNo=trans.bookNo;
total.units_sold=trans.units_sold;
total.revenue=trans.revenue;
}

}

std::cout<<total.bookNo<<" "<<total.units_sold<<" "<<total.revenue<<" ";
if (total.units_sold!=0)
{
std::cout<<total.revenue/total.units_sold<<std::endl;
}
else
{
std::cout<<"(No Sales)"<<std::endl;
}
return 0;
}
else
{
std::cerr<<"No Data?!"<<std::endl;
return -1;
}

}