《C++ Primer》第二章练习

2024-06-22 10:52
文章标签 c++ primer 第二章 练习

本文主要是介绍《C++ Primer》第二章练习,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

注意:每十道题给一个链接,一共 42 题

目录

        • 2.10 下列变量的初值分别是什么?
        • 2.20 请叙述下面这段代码的作用。
        • 2.30 对于下面这些语句,请说明对象被声明成了顶层 const 还是 底层 const ?
        • 2.40 根据自己的理解写出 Sales_data 类,最好与书中的有所区别。

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

答:类型int、long、long long 和 short 的区别是所占位数不同,能表示的整数范围不同。无符号类型只能表示0和正数,而有符号类型既可以表示正数也能表示负数,有符号类型的最高为用作符号位,0为正,1为负,而无符号所有位均表示值。float 和 double 的区别是所占位数不同,能表示的值的范围也不同,精度也不同。

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

答:利率应为 double 类型,一般包含小数。本金和付款应选择整形 unsigned int ,因为不存在负数,且贷款一般都是整数,而 unsigned int 类型的范围在0-42亿左右,够用。

2.3 读程序写结果。

unsigned u = 10, u2 = 42;
cout << u2 - u << endl;
cout << u - u2 << endl;int i = 10, i2 = 42;
cout << i2 - i << endl;
cout << i - i2 << endl;
cout << i - u << endl;
cout << u - i << endl;

答:同级别的有符号类型和无符号类型进行算数运算,有符号类型会自动转换为无符号类型。而无符号类型不可能出现负数,当出现负数时,结果为该负数加上该无符号类型的最大值再加1。

输出结果如下:
32
-32 + 4294967295 + 1 = 4294967264
32
-32
0
0

2.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、char字符串、wchar_t字符串,区别:char和wchar_t所占位数不同,表示范围不同
b. 类型:int、unsigned、long、unsigned long、int、int,区别:类型所占位数不同,表示范围不同,无符号类型只能表示0和正数,有符号类型既能表示整数也能表示负数。八进制整数以0开头,十六进制整数以0X或者0x开头。
c. 类型:double、float、long double,区别:类型所占位数不同,表示范围不同,精度不同。
d. 类型:int、unsigned、double、double,区别:浮点数能表示小数,且相比于整型表示范围更大,但是有精度限制。浮点数有小数表示法和科学计数表示法两种表示方法。

2.6 下面两组定义是否有区别,如果有,请叙述之:
int month = 9,day = 7;
int month = 09,day = 07;

答:第一行使用的是十进制整形字面值,month的值为9,day的值为7。第二行使用八进制整形字面值,以0开头。但是编译器会报错,因为9超出了八进制的的表示范围。

2.7 下述字面值表示何种含义?它们各自的数据类型是什么?
(a)“Who goes with F\145rgus?\012”
(b)3.14e1L  (c)1024f  (d)3.14L

答:a. 该字面值为字符串,中间包含了两个转义字符,\145和\012分别表示字符 ‘f’ 和字符 ‘\n’。则结果为:Who goes with Fergus?
b. 浮点型字面值,且用科学计数法表示,后缀L表示该字面值的类型为long double。结果为3.14*10 = 31.4
c. 试图表示一个单精度浮点数,但是该形式在某些编译器中将报错,因为后缀f直接跟在了整数 1024 后面,而整型后缀中没有 f,需改写成 1024.f 或者 1024.0f 。
d. 浮点型字面值,后缀L表示为long double 类型。

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

答:字符’M’的ASCII码为77,换行符’\n’的ASCII码为10。代码如下:

cout << “2\x4d\012”;
cout << “2\tM\n”;

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. 错误,输入运算符的右侧需要一个明确的可以修改的变量名词,而不是定义变量。应修改为:
int input_value = 0;
std::cin >> input_value;
b. 错误,对于内置类型,列表初始化如果存在初始值丢失的风险,编译器将报错。而字面值 3.14 为double类型,赋值给 int 类型会发生截断,将失去小数部分,编译不通过。这是一种不被建议的窄化操作应修改为:
double i = { 3.14 };
c. 错误,声明多个变量时需要使用逗号将变量隔开,而不能直接使用赋值运算符链接。应修改为:
double salary, wage;
salary = wage = 9999.99;
d. 与 b 一样,这也是一种窄化操作,用 double 类型的字面值初始化 int 变量,将发生截断,丢弃小数部分。编译器将发出警告。

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

std::string global_str;
int global_int;
int main()
{
int local_int;
std::string local_str;
}

答:对于像 int 这种内置类型来说,若不初始化,则在函数中声明的变量(局部的)其值是随机的、不确定的;而在函数外声明的变量(全局的)其值被编译器设置为 0 。而对于string 这种类,其声明的对象若不显式初始化,则调用其默认构造函数进行初始化,而 string 的默认构造函数将其初始化为空串。则结果如下:
global_str —— 空串 —— 全局变量
global_int —— 0 —— 全局变量
local_int —— 随机值 —— 局部变量
local_str —— 空串 —— 局部变量

2.11 指出下面的语句是声明还是定义:
(a)extern int ix = 1024;
(b)int iy;
(c)extern int iz;

答:a. 赋初始值的操作抵消了关键字 extren 的作用,所以该语句为定义
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. 违法,使用违法字符’-’
d. 违法,变量名使用数字开头

2.13 下面程序中 j 的值是多少?
int i = 42;
int main()
{
int i = 100;
int j = i;
}

答:局部变量和全局变量同名,在局部变量的作用域中,局部变量隐藏全局变量,所以 j 的值为 100。

2.14 下面的程序合法吗?如果合法,它将输出什么?
int i = 100, sum = 0;
for (int i = 0; i != 10; ++i)
  sum += i;
std::cout << i " " << sum << std::endl;

答:合法,第一个 i 在整个程序中均可见,第二个 i 只在for循环中可见,sum 中存储了 1-9 的和,最后输出的结果为:
100 45

2.15 下面的哪个定义是不合法的?为什么?
(a)int ival = 1.01;  (b)int& rval1 = 1.01;
(c)int& rval2 = ival;  (d)int& rval3;

答:a. 正确,但是 double 字面值赋值给 int 变量会产生截断,失去小数部分,编译器会发出警告。
b. 不合法,1.01 是 const double 类型,而 rval1 是 int 引用。
c. 合法
d. 不合法,由于引用只能绑定一个对象,且绑定了以后不能修改,所以引用必须初始化。

2.16 考察下面的所有赋值然后回答:哪些赋值时不合法的?为什么?哪些赋值是合法的?它们执行了什么样的操作?
 int i = 0, &r1 = i;  double d = 0, &r2 = d;
(a)r2 = 3.14159;  (b)r2 = r1;
(c)i = r2;      (d)r1 = d;

答:a. 合法,r2 是 d 的引用,所以相当于给 d 赋值 3.14159 。
b. 合法,把 i 的值赋给 d,d 的值为 0 。
c. 合法,把 d 的值赋值给 i,是窄化操作,编译器会警告。
d. 合法,和 c 的语句是一样的效果。

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

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

答:ri 是指向 i 的引用,所以 ri 改变相当于 i 改变。输出结果如下:
10 10

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

答:

int a = 1, b = 2;
int* pi = &a;  // 指针初始化指向a
pi = &b;  // 更改指针的值,指向b
*pi = 3;  // 更改指针指向对象的值,b的值变为3

2.19 请说明指针的引用的主要区别。

答:
(1)指针是一个对象,有自己的空间,存储指向对象的地址;引用只是其他对象的别名,没有自己的空间。
(2)引用必须初始化,且绑定对象之后不能改变。指针可以不初始化,如果是局部变量那么该指针所指向的位置是随机的,如果是全局变量,该指针为空指针。而且指针可以指向类型复合的其他对象。

2.20 请叙述下面这段代码的作用。
int i = 42;
int *p1 = &i;
*p1 = *p1 * *p1;

答:通过指针 p1 指向 i 来访问变量 i 的值,并把 i 的值修改为 42 的平方。

2.21 请解释下述定义。这些定义中有非法的吗?如果有,为什么?
 int i = 0;
(a)double* dp = &i;  (b)int* ip = i;  (c)int* p = &i;

答:a. 非法,double 类型的指针需要与 double 类型对象的地址相匹配。
b. 非法,指针存储该对应类型对象的地址,而不是对象本身。

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

if (p)  // ...
if (*p)  // ...

答:第一行:该判断条件检验的是存储在变量 p 中的地址,如果指针 p 指向一个真实存在的变量,那么其值一定不为0 。则判断条件为真。如果 p 为空指针,则判断条件为假。若 p 未指向任何对象或者为无效指针,则将引发不可估计的结果。

第二行:该判断条件检验的是变量 p 指向的对象的内容,上述指向对象的类型为 int,若其值为0,则判断条件为假,若其值非0,则判断条件为真。

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

答:在编写程序的过程中,应尽量给所有指针初始化,并且尽可能等定义了对象以后在定义指向它的指针。如果实在不知道指针指向何处,就把它初始化为 nullptr 或 0 。
判断:作者用的环境是 visual studio 2022 ,如果使用了未初始化的局部变量编译器会报错。一种判断方法是把该指针放入 if 条件中,若该指针指向了合法对象则 if 条件语句块顺利执行,若跳过了该语句块,则说明该指针指向了非法对象。

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

int i = 42;		void* p = &i;		long* lp = &i;

答:void 类型的指针可以指向任意类型的对象,所以 p 合法。而 long 类型的指针不能指向 int 类型的对象,因此 lp 非法。

2.25 说明下列变量的类型和值。
(a)int* ip, i, &r = i;(b)int i, *ip = 0;(c)int* ip, ip2;

答:a. ip 是 int 类型的指针,其值为随机值;i 是 int 类型的变量,其值为随机值;r 是 int 类型的引用。
b. i 是 int 类型的变量,其值为随机值;ip 是 int 类型的指针,它不指向任何对象,其值为 0(nullptr)。
c. ip 是 int 类型的指针,ip2 是 int 类型的变量。二者均未初始化,所以均为随机值。

2.26 下面哪些句子是合法的?如果有不合法的句子,请说明为什么?
(a)const int buf;   (b)int cnt = 0;
(c)const int sz = cnt; (d)++cnt; ++sz;

答:a. 不合法,const 对象一旦创建就不能修改,所以必须初始化。
d. 不和法,const 对象创建以后不能被修改。

2.27 下面的哪些初始化是合法的?请说明原因。
(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. 不合法,0 是字面常量,需使用 const 引用。
f. 引用必须初始化,且引用本身不是对象,因此不能让引用本身恒定不变。

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

(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. 不合法,定义了 int 类型变量 i,和指向 int 类型的常量指针 cp,但是并没有初始化 cp。const 对象必须初始化。
b. 不合法,定义了两个指向 int 类型的指针,其中一个为常量指针,但是没有初始化。
c. 不合法,定义了 int 类型常量 ic,和对 int 类型常量的引用 r,r 指向 ic。但是,ic 并未初始化。
d. 不合法,定义了一个指向 int 类型常量的常量指针,但并没有初始化。
e. 合法,定义了一个指向 int 类型常量的指针,但并没有初始化。

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

(a) i = ic;		(b) p1 = p3;
(c) p1 = &ic;	(d) p3 = &ic;
(e) p2 = p1;	(f) ic = *p3;

答:a. 合法,常量 ic 赋值给了变量 i。
b. 不合法,试图把常量的地址赋值给普通指针。
c. 不合法,和 b 的错误一样。
d. 不合法,p3 是一个常量指针,不能被赋值。
e. 不合法,p2 是一个常量指针,不能被赋值。
f. 不合法,ic 是常量,不能被修改。

2.30 对于下面这些语句,请说明对象被声明成了顶层 const 还是 底层 const ?
const int v2 = 0;	int v1 = v2;
int *p1 = &v1, &r1 = v1;
const int *p2 = &v2, *const p3 = &i, &r2 = v2;

答:v2 是顶层 const,p2 是底层 const, p3 既是顶层 const,又是底层 const,r2 是底层 const。

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

答:第一句:合法,普通引用指向普通变量。
第二句:不合法,普通指针不能指向常量,p2 具有底层 const 而 p1 是普通指针。
第三句:合法,指向常量的指针可以指向普通变量,普通指针可以转变为底层 const。
第四句:不合法,和第二句一样。
第五句:合法,两者都具有相同的底层 const。

2.32 下面的代码是否合法?如果非法,请设法将其修改正确。
  int null = 0, *p = null;

答:不合法,试图把 int 类型的值赋值给指向 int 类型的指针。修改后:
int null = 0, *p = nullptr;

2.33 利用本节定义的变量,判断下列语句的运行结果。
a = 42; b = 42; c = 42;
d = 42; e = 42; g = 42;

答:a. 正确运行。
b. 正确运行。
c. 正确运行。
d. 错误,d 是指向 int 类型的指针。
e. 错误,e 是指向 const int 类型的指针。
g. 错误,g 是指向 const int 类型的引用,不能赋值。

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

答:如下代码,下三条赋值语句编译阶段就出现错误。
在这里插入图片描述

2.35 判断下列定义推断出的类型是什么,然后编写程序进行验证。
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 关于下面的代码,请指出每一个变量的类型以及程序结束时它们各自的值。
int a = 3, b = 4;
decltype (a) c = a;
decltype ((b)) d = a;
++c;
++d;

答:a 为 int 类型,程序结束时其值为 4。b 为 int 类型,程序结束时其值为 4。c 为 int 类型,程序结束时其值为 4。d 为 int 类型的引用,程序结束时,其值为 4。

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

答:a 为 int 类型,其值为 3,。b 为 int 类型,其值为 4,。c 为int类型,其值为3。d 为 int 类型的引用,指向变量 a,其值为3。

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

答:第一,auto 类型说明符用编译器计算变量的初始值来推断其类型,而 decltype 虽然也让编译器分析表达式并得到它的类型,但是不实际计算表达式的值。
第二,编译器推断出来的 auto 类型有时候和初始值的类型并不完全一样,编译器会适当地改变结果类型使其更符合初始化规则。例如,auto 一般会忽略掉顶层 const,而把底层 const 保留下来。与之相反,decltype 会保留变量的顶层 const。
第三,与 auto 不同,decltype 的结果类型和表达式形式密切相关,如果变量名加上了一对括号,则得到的类型与不加括号时会有不同,如果 decltype 使用的是一个不加括号的变量,则得到的结果就是该变量的类型。如果给变量加上了一层或多层括号,则编译器将推断得到引用类型。

例子:

int i = 1;
const int j = 2;
auto a = i; decltype (i)b = i;  // 类型相同
auto c = j; decltype (j)d = j;  // 类型不同

类型相同:a 和 b 都是 int类型
类型不同:c 是 int 类型,而 d 是const int 类型。

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

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

答:该程序无法编译通过,结构声明结尾少了一个分号。
在这里插入图片描述

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

答:

// 头文件
#include <string>// Sales_data 结构声明
struct Sales_data
{std::string book_number;  // 书籍编号std::string book_name;  // 书名double price;  // 价格int sale_num;  // 销售量
}

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

答:类定义和main()函数放在一个文件中,类声明在main()函数上方,而类方法定义在main()函数下方。这个能看懂就看,这本书没点基础不好学,把后面的东西都放到前面来了,我写的也比较简洁。

// 头文件
#include <iostream>
#include <string>// using 声明
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::istream;
using std::ostream;// Sales_data 类声明
class Sales_data
{
private:string book_number;string book_name;double _price;int sale_num;double income;
public:// 构造函数Sales_data();Sales_data(const string& number, const string& name,double price, double num);// 友元函数friend istream& operator>>(istream& is, Sales_data& sd);friend ostream& operator<<(ostream& os, const Sales_data& sd);friend bool operator<(const Sales_data& sd1, const Sales_data& sd2);friend bool operator==(const Sales_data& sd1, const Sales_data& sd2);// 其他函数Sales_data& operator+=(const Sales_data sd);Sales_data operator+(const Sales_data sd);const string& GetNumber() const { return book_number; }  // 获取书籍编号
};int main()
{// 1.20Sales_data temp;while (cin >> temp){cout << temp;}// 1.21 Sales_data sd1, sd2;cin >> sd1 >> sd2;cout << sd1 + sd2 << endl;// 1.22Sales_data input;while (cin >> input){temp += input;}cout << input << endl;// 1.23int n = 0;string number;while (cin >> temp){if (number == "")number == temp.GetNumber();  // 获取输入书籍编号if (number == temp.GetNumber()){++n;}else{cout << number << " : " << n << "次\n";// 记录下一本书number = temp.GetNumber();n = 1;}}// 输出最后一本书cout << number << " : " << n << "次\n";// 1.24// 输入记录测试 1.23 的程序return 0;
}// Sales_data 类方法定义// 构造函数
Sales_data::Sales_data(): book_number(""), book_name(""), _price(0.0), sale_num(0), income(_price * sale_num)
{}Sales_data::Sales_data(const string& number, const string& name,double price, double num): book_number(number), book_name(name), _price(price), sale_num(num), income(_price* sale_num)
{}// 友元函数
istream& operator>>(istream& is, Sales_data& sd)
{// 输入信息cout << "Enter the information of the book: ";cin >> sd.book_number >> sd.book_name >> sd._price>> sd.sale_num;sd.income = sd._price * sd.sale_num;
}ostream& operator<<(ostream& os, const Sales_data& sd)
{// 输出信息cout << "Book number: " << sd.book_number << endl;cout << "Book name: " << sd.book_name << endl;cout << "Price: " << sd._price << endl;cout << "Sale number: " << sd.sale_num << endl;cout << "Income: " << sd.income << endl;
}bool operator<(const Sales_data& sd1, const Sales_data& sd2)
{return sd1.income < sd2.income;
}bool operator==(const Sales_data& sd1, const Sales_data& sd2)
{return sd1.book_number == sd2.book_number;
}Sales_data& Sales_data::operator+=(const Sales_data sd)
{// 把第二条记录加在第一条上面_price = (_price + sd._price) / 2;sale_num += sd.sale_num;income += sd.income;// 返回return *this;
}Sales_data Sales_data::operator+(const Sales_data sd)
{// 存储两个记录的和Sales_data temp;temp.book_number = sd.book_number;temp.book_name = sd.book_name;temp._price = (_price + sd._price) / 2;temp.sale_num = sale_num + sd.sale_num;temp.income = income + sd.income;// 返回return temp;
}

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

答:代码和上一题的基本没变,就是把类的声明和定义放入头文件中去了而已,我们只需要在 main() 函数文件中包含该头文件就可以。

在这里插入图片描述

Sales_data.h 头文件

#pragma once// 头文件
#include <iostream>
#include <string>// using 声明
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::istream;
using std::ostream;// Sales_data 类声明
class Sales_data
{
private:string book_number;string book_name;double _price;int sale_num;double income;
public:// 构造函数Sales_data();Sales_data(const string& number, const string& name,double price, double num);// 友元函数friend istream& operator>>(istream& is, Sales_data& sd);friend ostream& operator<<(ostream& os, const Sales_data& sd);friend bool operator<(const Sales_data& sd1, const Sales_data& sd2);friend bool operator==(const Sales_data& sd1, const Sales_data& sd2);// 其他函数Sales_data& operator+=(const Sales_data sd);Sales_data operator+(const Sales_data sd);const string& GetNumber() const { return book_number; }
};// Sales_data 类方法定义// 构造函数
Sales_data::Sales_data(): book_number(""), book_name(""), _price(0.0), sale_num(0), income(_price* sale_num)
{}Sales_data::Sales_data(const string& number, const string& name,double price, double num): book_number(number), book_name(name), _price(price), sale_num(num), income(_price* sale_num)
{}// 友元函数
istream& operator>>(istream& is, Sales_data& sd)
{// 输入信息cout << "Enter the information of the book: ";cin >> sd.book_number >> sd.book_name >> sd._price>> sd.sale_num;sd.income = sd._price * sd.sale_num;
}ostream& operator<<(ostream& os, const Sales_data& sd)
{// 输出信息cout << "Book number: " << sd.book_number << endl;cout << "Book name: " << sd.book_name << endl;cout << "Price: " << sd._price << endl;cout << "Sale number: " << sd.sale_num << endl;cout << "Income: " << sd.income << endl;
}bool operator<(const Sales_data& sd1, const Sales_data& sd2)
{return sd1.income < sd2.income;
}bool operator==(const Sales_data& sd1, const Sales_data& sd2)
{return sd1.book_number == sd2.book_number;
}Sales_data& Sales_data::operator+=(const Sales_data sd)
{// 把第二条记录加在第一条上面_price = (_price + sd._price) / 2;sale_num += sd.sale_num;income += sd.income;// 返回return *this;
}Sales_data Sales_data::operator+(const Sales_data sd)
{// 存储两个记录的和Sales_data temp;temp.book_number = sd.book_number;temp.book_name = sd.book_name;temp._price = (_price + sd._price) / 2;temp.sale_num = sale_num + sd.sale_num;temp.income = income + sd.income;// 返回return temp;
}

test1.cpp 测试文件

// 头文件
#include "Sales_data.h"int main()
{// 1.20Sales_data temp;while (cin >> temp){cout << temp;}// 1.21 Sales_data sd1, sd2;cin >> sd1 >> sd2;cout << sd1 + sd2 << endl;// 1.22Sales_data input;while (cin >> input){temp += input;}cout << input << endl;// 1.23int n = 0;string number;while (cin >> temp){if (number == "")number == temp.GetNumber();  // 获取输入书籍编号if (number == temp.GetNumber()){++n;}else{cout << number << " : " << n << "次\n";// 记录下一本书number = temp.GetNumber();n = 1;}}// 输出最后一本书cout << number << " : " << n << "次\n";// 1.24// 输入记录测试 1.23 的程序return 0;
}

这篇关于《C++ Primer》第二章练习的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1084085

相关文章

关于C++中的虚拟继承的一些总结(虚拟继承,覆盖,派生,隐藏)

1.为什么要引入虚拟继承 虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下: class A class B1:public virtual A; class B2:pu

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

C++的模板(八):子系统

平常所见的大部分模板代码,模板所传的参数类型,到了模板里面,或实例化为对象,或嵌入模板内部结构中,或在模板内又派生了子类。不管怎样,最终他们在模板内,直接或间接,都实例化成对象了。 但这不是唯一的用法。试想一下。如果在模板内限制调用参数类型的构造函数会发生什么?参数类的对象在模板内无法构造。他们只能从模板的成员函数传入。模板不保存这些对象或者只保存他们的指针。因为构造函数被分离,这些指针在模板外

C++工程编译链接错误汇总VisualStudio

目录 一些小的知识点 make工具 可以使用windows下的事件查看器崩溃的地方 dumpbin工具查看dll是32位还是64位的 _MSC_VER .cc 和.cpp 【VC++目录中的包含目录】 vs 【C/C++常规中的附加包含目录】——头文件所在目录如何怎么添加,添加了以后搜索头文件就会到这些个路径下搜索了 include<> 和 include"" WinMain 和

C/C++的编译和链接过程

目录 从源文件生成可执行文件(书中第2章) 1.Preprocessing预处理——预处理器cpp 2.Compilation编译——编译器cll ps:vs中优化选项设置 3.Assembly汇编——汇编器as ps:vs中汇编输出文件设置 4.Linking链接——链接器ld 符号 模块,库 链接过程——链接器 链接过程 1.简单链接的例子 2.链接过程 3.地址和

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C++学习 贝蒂的主页:Betty’s blog 1. 泛型编程 首先让我们来思考一个问题,如何实现一个交换函数? void swap(int& x, int& y){int tmp = x;x = y;y = tmp;} 相信大家很快就能写出上面这段代码,但是如果要求这个交换函数支持字符型

《offer来了》第二章学习笔记

1.集合 Java四种集合:List、Queue、Set和Map 1.1.List:可重复 有序的Collection ArrayList: 基于数组实现,增删慢,查询快,线程不安全 Vector: 基于数组实现,增删慢,查询快,线程安全 LinkedList: 基于双向链实现,增删快,查询慢,线程不安全 1.2.Queue:队列 ArrayBlockingQueue:

C++入门01

1、.h和.cpp 源文件 (.cpp)源文件是C++程序的实际实现代码文件,其中包含了具体的函数和类的定义、实现以及其他相关的代码。主要特点如下:实现代码: 源文件中包含了函数、类的具体实现代码,用于实现程序的功能。编译单元: 源文件通常是一个编译单元,即单独编译的基本单位。每个源文件都会经过编译器的处理,生成对应的目标文件。包含头文件: 源文件可以通过#include指令引入头文件,以使

C++面试八股文:std::deque用过吗?

100编程书屋_孔夫子旧书网 某日二师兄参加XXX科技公司的C++工程师开发岗位第26面: 面试官:deque用过吗? 二师兄:说实话,很少用,基本没用过。 面试官:为什么? 二师兄:因为使用它的场景很少,大部分需要性能、且需要自动扩容的时候使用vector,需要随机插入和删除的时候可以使用list。 面试官:那你知道STL中的stack是如何实现的吗? 二师兄:默认情况下,stack使

剑指offer(C++)--孩子们的游戏(圆圈中最后剩下的数)

题目 每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去