2.1:类型int、long、long long和short的区别是什么?无符号类型和带符号类型的区别是什么?float和double的区别是什么?
short 、int、 long、 long long 表示不同尺寸的整数,其所占内存空间大小不同,能表示的数据范围也自然不同。通常来讲, short 最小 long long 最大。而根据 c++ 标准的规定,shrot类型最小为16位,int类型最小为16位,long 类型最小为32位, long long 类型最小为64位。且一个int至少和一个short一样大,一个long至少和一个int一样大,一个long long至少和一个long一样大。
float 和 double都表示浮点数,但他们所能表示的数据范围和精度有所不同。通常,float以1个字(32比特)来表示,double以2个字(64比特)来表示(这也是float被称为单精度,而double被称为双精度的原因,64/32=2),long double以3或4个字(96或128比特)来表示。一般来说,类型float和double分别有7和16个有效位;类型long double则常常被用于有特殊浮点需求的硬件,它的具体实现不同,精度也各不相同。
2.2:计算按揭贷款时,对于利率、本金和付款分别应选择何种数据类型?说明你的理由。
利率,本金,付款都应该选择 double 类型。因为实际上他们都可能出现小数,因此只能从 float ,double 和 long double 中选择。long double 比较耗费性能,且对于这三者不需要那么高的精度,那么只剩float 和 double 可供选择。float精度小于double且二者性能消耗基本一致,在能使用float的地方完全可以替换为double。综上所述利率,本金,付款,都应该选用 double 类型。
2.3:读程序写结果。
#include <iostream>
int main() {
unsigned u = 10, u2 = 42;
std::cout << u2 - u << std::endl; // 32
std::cout << u - u2 << std::endl; // 4294967296 - 32 = 4294967264
int i = 10, i2 = 42;
std::cout << i2 - i << std::endl; // 32
std::cout << i - i2 << std::endl; // -32
std::cout << i - u << std::endl; // 0
std::cout << u - i << std::endl; // 0
return 0;
}
2.4:编写程序检查你的估计是否正确,如果不正确,请仔细研读本节直到弄明白问题所在。
运行结果:
32
4294967264
32
-32
0
0
2.5:指出下述字面值的数据类型并说明每一组内几种字面值的区别:
'a' char
L'a' wchar_t
"a" std::string
L"a" 宽字符型字符串
10 int
10u unsigned int
10L long
10uL unsigned long
012 八进制数
0xC 十六进制数
3.14 double
3.14f float
3.14L long double
10 int
10u unsigned int
10. double
/*
auto f = 10.;
std::cout << typeid(f).name() << std::endl;
result: d (证明 10. 为double类型,也符合在除非明确指定的情况下,浮点数默认为double类型)
*/
2.6:下面两组定义是否有区别,如果有,请叙述之:
有区别,以0开头为八进制,所以下面一组的month定义错误,数字9超出了8进制数所能表示的范围
2.7:下述字面值表示何种含义?它们各自的数据类型是什么?
(a)为一个字符串,包含两个转义字符,\145对应字符 e ,\012表示换行符
(b)为使用科学计数法表示的 long double 类型
(c)编译报错,应该改为 1024.f 此时表示单精度浮点数
(d)为 long double 类型
2.8:请利用转义序列编写一段程序,要求先输出2M,然后转到新一行。修改程序使其先输出2,然后输出制表符,再输出M,最后转到新一行。
#include <iostream>
int main() {
std::cout << 2 << "\115\012";
std::cout << 2 << "\t\115\012";
return 0;
}
2.9:解释下列定义的含义。对于非法的定义,请说明错在何处并将其改正。
(a)错误,因为输入运算符右侧需要一个明确的变量名称,而不能是一个定义变量的语句,改正后如下:
int input_value;
std::cin >> input_value;
(b)错误,使用列表初始化时不允许发生窄化操作,改正后如下:
float i = {3.14};
(c)错误,wage未定义而被直接使用,改正后如下:
double salary = 9999.99, wage = salary;
(d)会发生精度损失,但程序正确运行
2.11:指出下面的语句是声明还是定义:
extern int ix = 1024; // 定义
int iy; // 声明并定义
extern int iz; // 声明
2.12:请指出下面的名字中哪些是非法的?
(a)非法,double为系统关键字
(c)非法,标识符中只能出现字母,数字,和下划线
(d)非法,标识符必须以字母或下划线开头
2.13:下面程序中j的值是多少?
int i = 42;
int main() {
int i = 100;
int j = i;
return 0;
}
j 为100,在main函数的作用域中包含一个名为i的int型变量,则不会再去全局作用于中查找i
2.14:下面的程序合法吗?如果合法,它将输出什么?
int main() {
int i = 100, sum = 0;
for (int i = 0; i != 10; ++i) {
sum += i;
}
std::cout << i << " " << sum << std::endl;
return 0;
}
合法,输出 100 45,因为在for 循环体中有局部的i变量,因此实际上sum的值为1-9累加的结果
2.15:下面的哪个定义是不合法的?为什么?
(b)非法,引用只能绑定在某个对象上,而不能与字面值或某个表达式的计算结果绑定在一起
(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)合法,把 3.1415 赋给 d
(b)合法,把 i 的值赋给 d
(c)合法,把 d 的值赋给 i
(d)合法,把d的值赋给 i
2.17:执行下面的代码段将输出什么结果?
int main() {
int i, &ri = i;
i = 5;
ri = 10;
std::cout << i << " " << ri << std::endl;
return 0;
}
输出 10 10 ,因为 ri 为对 i 的引用,对 ri 赋值就是对 i 赋值
2.18:编写代码分别更改指针的值以及指针所指对象的值。
#include <iostream>
int main() {
int age = 99;
int *ap = nullptr;
// 更改指针的值,使指针指向age
ap = &age;
// 通过指针更改age的值
*ap = 25;
// 输出25
std::cout << age << std::endl;
return 0;
}
2.19:说明指针和引用的主要区别。
1. 指针是对象而引用不是
2. 指针不需要在定义时赋初值,而引用需要
3. 指针是指向内存中的某个对象,而引用是内存中某个对象的别名
2.20:请叙述下面这段代码的作用。
int i = 42;
int *p1 = &i;
*p1 = *p1 * *p1;
通过指针操作 i 的值,令其等于自身的平方
2.21:请解释下述定义。在这些定义中有非法的吗?如果有,为什么?
int i = 0;
(a) double *dp = &i;
(b) int *ip = i;
(c) int *p = &i;
(a)非法,
2.22:假设p是一个int型指针,请说明下述代码的含义。
if(p) 判断 p 是否为空指针
if(*p)判断 p 所指的对象是否为空
2.23:给定指针p,你能知道它是否指向了一个合法的对象吗?如果能,叙述判断的思路;如果不能,也请说明原因。
不能知道,只能判断p是否为空指针,而不能确定当它不是空指针时是否指向了一个合法的对象(基于目前的知识)
2.24:在下面这段代码中为什么p合法而lp非法?
因为 void * 是一种特殊指针,它可以存放任意类型对象的地址,而long * 只能指向 long 类型的变量或者指向空指针
2.25:说明下列变量的类型和值。
int * ip, i, &r = i ; ip 为指向 int 的无效指针,i 为int型变量,如果该语句在全局作用域中则 i 为0,否则 i 也未初始化,r为对 i 的引用,值和 i 相同
int i, * ip = 0 ; i 为整型,如果在全局作用于 i 值为0 否则 i 未初始化。ip为指向int型的指针,值为0,表示空指针
int * ip , ip2 ; ip 为指向 int 类型的无效指针,ip2 为整型,值未初始化
2.26:下面哪些句子是合法的?如果有不合法的句子,请说明为什么?
(a) 不合法,常量必须在定义的时候初始化
(d) 不合法,常量不能执行自增和赋值操作
2.27:下面的哪些初始化是合法的?请说明原因。
(a) 不合法,引用必须指向一个对象,而不能是字面值
(f) 不合法,const对引用的修饰只限于顶层const
2.28:说明下面的这些定义是什么意思,挑出其中不合法的。
(a)不合法,对于底层 const 修饰的指针必须在定义时初始化
(b)不合法,同(a)
(c)不合法,常量 ic 必须在定义时初始化
(d)不合法,指针常量必须在定义时初始化
2.29:假设已有上一个练习中定义的那些变量,则下面的哪些语句是合法的?请说明原因。
(b)不合法,p3为指向常量的指针,不能转换为一个普通指针
(c)不合法,ic为一个常量,不能将其取地址的结果赋给一个普通指针
(d)不合法,p3为指针常量,不能对其进行赋值操作
(e)不合法,p2为指针常量,不能对其进行赋值操作
(f)不合法,ic是常量,不能对其执行赋值操作
2.30:对于下面的这些语句,请说明对象被声明成了顶层const还是底层const?
const int v2 = 0; // v2 顶层const
int v1 = v2;
int *p1 = &v1, &r1 = v1;
const int *p2 = &v2, *const p3 = &i, &r2 = v2;
// p2 底层const, p3 顶层const和底层const, r2 顶层const
2.31:假设已有上一个练习中所做的那些声明,则下面的哪些语句是合法的?请说明顶层const和底层const在每个例子中有何体现。
r1 = v2; // 合法
p1 = p2; // 不合法
p2 = p1; // 合法
p1 = p3; // 不合法
p2 = p3; // 合法
2.32:下面的代码是否合法?如果非法,请设法将其修改正确。
改正如下:
int null = 0, *p = nullptr;
2.33:利用本节定义的变量,判断下列语句的运行结果。
int i = 10, &r = i;
const int ci = i, &cr = ci;
auto a = r;
auto b = ci;
auto c = cr;
auto d = &i;
auto e = &ci;
auto &g = ci;
a=42 合法
b=42 合法
c=42 合法
d=42不合法,d是一个 int 型指针,不能直接将数值赋给他
e=42不合法,同上
g=42不合法,g为对常量的引用,不能对其重新赋值
2.34:基于上一个练习中的变量和语句编写一段程序,输出赋值前后变量的内容,你刚才的推断正确吗?如果不对,请反复研读本节的示例直到你明白错在何处为止。
正确
2.35:判断下列定义推断出的类型是什么,然后编写程序进行验证。
const int i = 42;
auto j = i; const auto &k = i; auto *p = &i;
const auto j2 = i, &k2 = i;
i 为整型常量
j 为非常量整型
k 为对常量的引用
p 为指向常量的指针
j2 为整型常量
k2 为对常量的引用
2.36:关于下面的代码,请指出每一个变量的类型以及程序结束时它们各自的值。
int a = 3, b = 4;
decltype(a) c = a;
decltype((b)) d = a;
++c;
++d;
a为整型
b为整型
c为整型
d为 int &
a b c d 的值都等于 4
2.38:说明由decltype指定类型和由auto指定类型有何区别。请举出一个例子,decltype指定的类型与auto指定的类型一样;再举一个例子,decltype指定的类型与auto指定的类型不一样。
auto 一般会忽略掉顶层 const 属性,而 decltype 则不会
当引用被用作初始值时,编译器会以引用对象的类型作为 auto 的类型
decltype((variable)) 一定会产生一个引用
decltype 使用的表达式是一个变量时,一定会返回该变量的类型,包括 const 和引用
const int a = 10;
auto b = a; // b int
decltype(a) c = a; // c const int
2.39:编译下面的程序观察其运行结果,注意,如果忘记写类定义体后面的分号会发生什么情况?记录下相关信息,以后可能会有用。
struct Foo {
}
int main() {
return 0;
}
error: expected ';' after struct
2.40:根据自己的理解写出Sales_data类,最好与书中的例子有所区别。
struct Sale_data {
std::string bookNo;
std::string bookName;
unsigned units_sold = 0; // 销售量
double selling_price = 0.0; // selling
double price = 0.0; // 定价
double discount = 0.0; // 折扣
};
2.41:使用你自己的Sales_data类重写1.5.1节(第20页)、1.5.2节(第21页)和1.6节(第22页)的练习。眼下先把Sales_data类的定义和main函数放在同一个文件里。
1.2.0
#include <iostream>
struct Sale_data {
std::string bookNo;
std::string bookName;
unsigned units_sold = 0; // 销售量
double selling_price = 0.0; // selling
double price = 0.0; // 定价
double discount = 0.0; // 折扣
};
int main() {
Sale_data sale;
std::cerr << "请输入一组销售记录" << std::endl;
std::cin >> sale.bookNo >> sale.units_sold >> sale.selling_price;
std::cout << sale.bookNo << " " << sale.units_sold << sale.selling_price * sale.units_sold;
return 0;
}
1.2.1
#include <iostream>
struct Sale_data {
std::string bookNo;
std::string bookName;
unsigned units_sold = 0; // 销售量
double selling_price = 0.0; // selling
double price = 0.0; // 定价
double discount = 0.0; // 折扣
};
int main() {
Sale_data sale1, sale2;
std::cerr << "请输入两条 isbn 相同的销售记录" << std::endl;
std::cin >> sale1.bookNo >> sale1.units_sold >> sale1.selling_price;
std::cin >> sale2.bookNo >> sale2.units_sold >> sale2.selling_price;
if (sale1.bookNo == sale2.bookNo) {
std::cout << sale1.bookNo << " " << sale1.units_sold + sale2.units_sold
<< sale1.selling_price * sale1.units_sold + sale2.selling_price * sale2.units_sold;
} else {
std::cerr << "两条销售记录的 isbn 编号必须相同";
return -1;
}
return 0;
}
1.2.2
#include <iostream>
struct Sale_data {
std::string bookNo;
std::string bookName;
unsigned units_sold = 0; // 销售量
double selling_price = 0.0; // selling
double price = 0.0; // 定价
double discount = 0.0; // 折扣
};
int main() {
Sale_data total, sale;
std::cerr << "请输入多条 isbn 相同的销售记录" << std::endl;
if (std::cin >> total.bookNo >> total.units_sold >> total.selling_price) {
double revenue = total.selling_price * total.units_sold;
while (std::cin >> sale.bookNo >> sale.units_sold >> sale.selling_price) {
if (total.bookNo == sale.bookNo) {
total.units_sold += sale.units_sold;
revenue += sale.selling_price * sale.units_sold;
} else {
std::cerr << "输入了 isbn 不相同的销售记录";
return -1;
}
}
std::cout << total.bookNo << total.units_sold << revenue;
} else {
std::cerr << "错误的销售记录";
return -1;
}
return 0;
}
2.42:根据你自己的理解重写一个Sales_data.h头文件,并以此为基础重做2.6.2节(第67页)的练习。
略,后期解答