答案目录

第2章 变量和基本类型

练习2.1

int最小尺寸为16位, 2个字节; long最小尺寸为32位, 4个字节; long long最小尺寸为64位, 8个字节; short最小尺寸为16位, 2个字节;

带符号类型可以表示整数、负数和0, 无符号类型仅能表示大于等于0的值且所有比特都用来存储值;

float和double都是浮点类型, float最小尺寸为6位有效数字, double为10位;

练习2.2

利率:unsigned double; 本金和付款:unsigned float

利率一般小数位数较多, 且没有负数; 本金和付款小数位数少, 也没有负数; unsigned可以节约字节数

练习2.3

1
2
3
4
5
6
7
#include <iostream>
int main()
{
unsigned u = 10, u2 = 42;
std::cout << u - u2 << std::endl;
return 0;
}

这一段产生逸出, 输出结果为4294967264, 无符号数相减可以得到0;

假设int占32位, unsigned类型中 -1 对应4294967295 2的32次方为4294967296

练习2.5

(a) ‘a’ 字符字面值, L’a’ 宽字符字面值, 类型是wchar_t, “a” 字符串字面值, L"a" 宽字符字符串字面值;

(b)10 十进制, 10u 无符号整型, 10L 长整型, 10uL 无符号长整型, 012 八进制, 0xC 十六进制;

©3.14 浮点数, 3.14f 单精度浮点型字面值, 类型是float, 3.14L 扩展精度浮点型字面值, 类型是long double;

(d)10 十进制, 10u 无符号整型, 10. 浮点型, 10e-2 浮点型字面值;

练习2.6

1
2
int month = 9, day = 7;    //定义的month和day均为10进制
int month = 09, day = 07; // 定义的month和day为八进制,month会报错,因为09超出范围了

练习2.7

1
2
3
4
5
(a)"who goes with F\145rgus?\012"   
// \145表示小写字母“e”, \012表示换行符。 输出:who goes with Fergus?
(b) 3.14e1L // 表示扩展的浮点型,类型是long double
(c) 1024f // 单精度浮点型字面值,类型是float
(d) 3.14L // 表示扩展的浮点型,类型是long double

在泛化的转义序列中\141为a,\101为A

练习2.8

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

练习2.9

1
2
3
4
(a) std::cin >> int input_value          // 错误,不能在输入输出语句中定义变量。
(b) int i = { 3.14 }; // 错误,在初始化列表中使用浮点型初始化int变量可能会丢失数据,编译器会拒绝执行
(c) double salary = wage = 9999.99; // wage未定义,如果wage定义了,则该语句可以正常执行,最终wage和salary相等(从右到左)
(d) int i = 3.14; // 警告,有隐式转化,i值为3。

练习2.10

报错,未知的初始值

练习2.11

1
2
3
(a) extern int ix = 1024;    // 定义 (任何包含了显式初始化的声明即成为定义)
(b) int iy; // 声明并定义 (想声明而不定义,就在变量名前家extern)
(c) extern int iz; // 声明

练习2.12

变量名只能包含字母、数字、下划线,且不能和关键词等重复,不能以数字开头

1
2
3
4
5
(a) int doube = 3.14;    //非法,double为关键字,不能作为变量名
(b) int _; //合法
(c) int catch-22; //非法,变量名只能包含字母、数字、下划线
4int 1_or_2 = 1; //非法,不能以数字开头
5double Double = 3.14; //合法

练习2.13

j = 100

1
2
3
4
5
6
7
8
9
#include <iostream>
int i = 42;
int main()
{
int i = 100;
int j = i;
std::cout << j << std::endl;
return 0;
}

练习2.14

合法,输出100 45

1
2
3
4
5
6
7
8
9
#include <iostream>
int main()
{
int i = 100, sum = 0;
for (int i = 0; i != 10; ++i)
sum += i;
std::cout << i << " " << sum << std::endl;
return 0;
}

练习2.15

1
2
3
4
(a) int ival = 1.01;     //用float初始化int,不合法,会有警告
(b) int &rval1 = 1.01; //非法,引用的初始值必须是一个对象
(c) int &rval2 = ival; //合法
(d) int &rval3; //非法,引用必须被初始化。

练习2.16

1
2
3
4
5
6
7
int i = 0, &rl = i;
double d = 0, &r2 = d;

(a) r2 = 3.14159; //合法,d的值也变为3.14159
(b) r2 = r1; //合法,但隐式转化
(c) i = r2; //合法,但隐式转化
(d) r1 = d; //合法,但隐式转化

练习2.17

10 10

1
2
3
4
5
6
7
8
9
#include <iostream>
int main()
{
int i, & ri = i;
i = 5;
ri = 10;
std::cout << i << " " << ri << std::endl;
}

练习2.19

(1)引用在定义时必须初始化,而指针可不初始化;

(2)引用在其生命周期内,只能指向一个对象,而指针可以先后指向不同的对象

(3)指针本身就是一个对象,允许对指针进行赋值和拷贝

练习2.20

让i值变为i平方

1
2
3
4
5
6
7
8
#include <iostream>
int main()
{
int i = 42;
int* pi = &i;
*pi = *pi * *pi;
std::cout << *pi << std::endl;
}

练习2.21

1
2
3
(a) double* dp = &i;     //非法,不能用int型的变量初始化doube指针
(b) int* ip = i; //非法, 不能用int值初始化指针
(c) int* p = &i; //合法

练习2.22

1
2
if (p) //如果地址不为0
if (*p) //如果所指的值为真,*p值非0

练习2.23

不行,如果你把指针理解为一个信封上的地址,那么没有任何手段能保证你填写的地址必然有人住。(别人的回答)

类比于有这个东西和是不是我要的东西;

练习2.24

1
2
3
int i = 42;
void *p = &i; //因为void指针类型可以存放任意对象的地址
long *lp = &i; //但是long指针,就只能存放long对象的地址

练习2.25

1
2
3
(a) int* ip, i, &r = i;     // ip 为int指针类型,i为int型,r为引用类型,初始化为i。
(b) int i, *p =0; // i为int型, p为int指针类型,初始化为0,并未指向任何对象
(c) int* ip, ip2; // ip为int指针类型,ip2为int型,未定义初始值

练习2.26

1
2
3
4
(a) const int buf;       // 不合法,声明一个const常量的同时必须初始化
(b) int cnt = 0; // 合法,声明并初始化一个int变量
(c) const int sz = cnt; // 合法,声明一个int const常量,并初始化。
(d) ++cnt; ++sz; // 不合法,sz为常量,不能进行++操作。

练习2.27

1
2
3
4
5
6
7
(a) int i = -1, &r = 0;      // 不合法, r为引用,初始化只能指向一个对象。
(b) int *const p2 = &i2; // 合法,定义一个int型的常量指针,初始化为i2的地址,之后指针的值不能再改变
(c) const int i = -1, &r = 0; // 合法, r为引用,const int &r = 0; 是合法的
(d) const int* const p3 = &i2; // 合法,p3的值不能改变,*p3也不能改变
(e) const int* p1 = &i2; // 合法,指针常量,p1指向的值不能被改变
(f) const int& const r2; // 不合法,引用不能是const
(g) const int i2 = i, &r = i; // 合法

练习2.28

1
2
3
4
5
(a) int i, *const cp;       // 不合法,定义const类型指针要初始化,cp
(b) int *p1, *const p2; // 不合法,同上,p2应该初始化。
(c) const int ic, &r = ic; // 不合法,ic为const类型,必须要初始化
(d) const int *const p3; // 不合法,p3需要初始化
(e) const int *p; // 合法,指向是常量,但指针的值可变

练习2.29

1
2
3
4
5
6
(a) i = ic;         // 合法
(b) p1 = p3; // 不合法,int* 不能用const int* 初始化
(c) p1 = &ic; // 不合法,p1是一个普通指针,不能指向const int类型的值。
(d) p3 = &ic; // 不合法,p3的值和p3指向的值都不能改变
(e) p2 = p1; // 不合法,p2的值不能被改变
(f) ic = *p3; // 不合法,ic是常量,不能被改变

练习2.30

靠右的const是顶层const,靠左的是底层const(针对指针的判断)

1
2
3
(a) const int v2 = 0; int v1 = v2;          // v2是顶层const
(b) int *p1 = &v1, &r1 = v1; // 非const,&ri为引用
(c) const int *p2 = &v2, *const p3 = &i, &r2 = v2; // p2是底层const,p3最左是底层,p3前面是顶层const, r2是底层const

顶层const可以进行赋值操作,但底层const有限制,拷入拷出的对象也必须具有相同的底层const,或者两个数据类型可以转换,一般来说非常量可以转换成常量,反之不行;

练习2.31

1
2
3
(a) r1 = v2;        // 合法,引用改变值
(b) p1 = p2; p2 = p1; // 不合法,p2是底层const,赋值对象必须同样有底层const才行,p2 = p1合法
(c) p1 = p3; p2 = p3; // 不合法,p3是底层const, p2 = p3合法。

练习2.32

1
2
int null = 0, *p = null;           
// int *p不能用int型来初始化。 应为 int null = 0, *p = &null / int *p = nullptr

练习2.33

1
2
3
4
(a) a = 42; b = 42; c = 42;         // a, b, c的值均为42
(b) d = 42; e = 42; g = 42; // d:error, d为int*类型
// e:error, e为const int*类型
// g:error, g为const int类型,不能再赋值

练习2.34

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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;
std::cout << a << b << c << std::endl;
std::cout << *d << *e << g << std::endl;
}

练习2.35

1
2
3
4
5
const int i = 42// i为const int类型
auto j = i; // j为int类型
auto &k = i; // k为const int& 类型
auto *p = &i; // p为const int* 类型
const auto j2 = i, &k2 = i; // j2为const int类型,k2为const int& 类型。

练习2.36

decltype((variable))(注意是双层括号)的结果永远是引用

1
2
3
4
5
int a = 3, b = 4;      //
decltype(a) c = a; // c为int类型,a为c的初值
decltype((b)) d = a; // d为int& 类型,是a的引用
++c; // ++c之后的值为4;不影响a值
++d; // ++d之后的值为4;影响a值,a变为4

练习2.37

1
2
3
int a = 3, b = 4;       // a, b均为int
decltype (a) c = a; // c为int
decltype (a = b) d = a; // d为int&,是a的引用,(a = b)不影响a值,并没有实际操作

练习2.38

相同点:都通过已知变量或表达式的类型来指定类型,如:

1
int i = 2auto j = i; decltype(i) j = i; //两者相同	

不同点:auto会忽略顶层const,但decltype不会;auto定义变量必须有初始值,但decltyple不一定;

如果使用引用类型,auto会识别为其所指对象的类型,decltype则会识别为引用的类型;

decltype(())双括号的差别,直接识别为引用类型;

1
2
3
4
5
6
7
int i = 0, &r = i;
// same
auto a = i;
decltype(i) b = i;
// different
auto c = r;
decltype(r) d = i;

练习2.40

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <string>
struct Sales_data
{
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
int main()
{
return 0;
}

练习2.41,2.42

{ % hideInline 发挥自己的想象力吧, 参考答案 % }