C++ Primer(第5版) 课后答案 第二章

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

int、long、long long和short都是整型,但它们在c++中标准规定的最小值不同,

类型含义最小尺寸
int整型16位
long短整型32位
long long长整型64位
short长整型16位

同时编译器也可以赋予这些类型更大的尺寸,某一类型所占比特数不同,表示的数据范围也不同。

整型(除了布尔型和扩展的字符型)可以划分为带符号的(signed)和无符号的(unsigned)两种。

带符号类型可以表示正数、负数和0,其最高位比特为符号位。

无符号类型仅能表示大于等于0的数,但其所有比特都用来存储数值。

float、double都是浮点数

类型含义最小尺寸有效位数
float单精度浮点数32位7个
double双精度浮点数64位16个

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

利率,本金和付款都用double型

因为它们既可能是整数,也可能是实数,long double提供的精度在这种情况是没有必要的,也造成了运行时的消耗,float通常精度不够,而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;  //4,294,967,264
    //模为2^32=4294967296
    //但u-u2=-32,是一个负数,我们需要将它转化为一个取模之后的值
    //取模后为4394967296-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
}

把负数转换成无符号数类似于直接给无法好书赋一个负值,结果等于这个负数加上无符号数模。 

当从无符号数中减去一个值,无论这个值是不是无符号数,都必须确保结果不能是一个负值。

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

字面值数据类型
'a'字符字面值
L'a'宽字符字面值(wchar_t)
"a"字符串字面值
L"a"

宽字符字符串字面值(wchar_t)

'a'表示的就是单独的字符a,字符串"a"表示了一个字符的数组,该数组包含两个字符:一个是字母a,一个是空字符。

字面值数据类型
10十进制整型字面值
10u无符号十进制整型字面值
10L十进制长整型字面值
10uL

无符号十进制长整型字面值

012八进制整型字面值
0xC十六进制整形字面值

字面值数据类型
3.14浮点型字面值 (double)
3.14f单精度浮点型字面值(float)
3.14L扩展精度浮点型字面值 (long double)

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

#include<iostream>
int main()
{
	int month = 9, day = 7;
    //month,day都被定义为整型并被初始化,分别为9和7

	int month = 09, day = 07;
    //month,day都被定义为整型
    //字面值以0开头表示是八进制整型字面值,而09却不符合八进制数,非法
}

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

字面值含义数据类型
"Who goes with F\145rgus?\012"\145表示e  \012表示换行符       字符串字面值
3.14e1L扩展精度浮点型字面值long double
1024f单精度浮点型字面值float
3.14L扩展精度浮点型字面值long double

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

#include<iostream>

int main()
{
	std::cout << "2\115\n";       //输出2M

	std::cout << "2\t\115\n";     //输出2       M
}

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

#include<iostream>
int main()
{
	std::cin >> int input_value;
	// >>运算符的作用是接受一个istream作为左侧运算对象,接受一个对象作为右侧运算对象
	//从istream中读入数据,存入到给定对象中
	//此语句右侧对象是未定义的,而且int是内置类型名无法作为标识符

	//应先定义再赋值,为了使程序可靠,应初始化每一个内置类型的变量
    //可改为
	int input_value = 0;
	std::cin >> input_value;

	int i = { 3.14 };
	//从double收缩转换到int型,列表初始化存在丢失信息的风险,编译器报错
    //可改为
	double i = { 3.14 };

	double salary = wage = 9999.99;
	//wage未定义,应先定义再赋值
    //可改为
	double wage = 0;
	double salary = wage = 9999.99;

	int i = 3.14;
	//自动类型转换,丢失了部分值
	//可改为
	double i = { 3.14 };
}

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

#include<iostream>

std::string global_str;		   //global_str非显式地初始化为一个空串

int global_int;				   //global_int定义在函数体外部,被初始化为0
int main()
{
	int local_int; 		       //local_int为int型  定义在函数体内部的内置函数不被初始化,报错

	std::string local_str;	   //local_str非显式地初始化为一个空串
}

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

(a) extern int ix = 1024;

 是定义,任何包含了初始化的声明即成为定义。

(b) int iy;

 声明并定义

(c) extern int iz;

 是声明

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

int main()
{
	int double = 3.14;		//非法

	int _;					//合法

	int catch - 22;         //非法

	int 1_or_2 = 1;         //非法

	double Double = 3.14;   //合法
}

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

int i = 42;
int main()
{
	int i = 100;
	int j = i;
}

j的值为100,因为给j赋值的i时局部变量,而非全局变量,因此赋值为100。

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

#include<iostream>
int main()
{
	int i = 100, sum = 0;

	//当i=10时循环结束
	for (int i = 0; i != 10; i++)
		sum += i;     //由于i被定义在循环里,因此是局部变量,作用域只在循环内部     
	//sum计算的是由0到9的整数和

	//循环结束后,循环内部定义的i不能再访问,因此输出的i值为函数开头定义的100
	std::cout << i << " " << sum << std::endl;
}
//输出 100 45

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

int main()
{ 
	int ival = 1.01;		//合法

	int &rvall = 1.01;		//不合法
	//引用类型的初始值必须是一个对象

	int &rval2 = ival;		//合法
	
	int &rval3;				//不合法
	//引用必须被初始化,而且和它的初始值绑定在一起
}

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

int main()
{
	int i = 0, &r1 = i;
	double d = 0, &r2 = d;

	r2 = 3.14159;		//合法,把3.14159赋给了d

	r2 = r1;			//合法,把与r1绑定的i的值赋给了d

	i = r2;				//合法,把与r2绑定的d的值赋给了i

	r1 = d;				//合法,把d的值赋给了与r1绑定的对象i
}

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

#include<iostream>
int main()
{
	int i, &ri = i;
    
//i赋值为5
	i = 5;  
//把10赋给与ri绑定的对象i 
	ri = 10;
	std::cout << i << " " << ri << std::endl;
}
//输出 10 10

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

#include<iostream>
int main()
{
	int val = 1, val2 = 0, * p = &val;
	//将val2的地址赋给指针p
	p = &val2;
	//解引用p,将5赋给val2
	*p = 5;
	std::cout << val << " " << val2 << std::endl;
}
//输出 1 5

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

引用本身不是一个对象,不允许初始化后令引用再绑定到另外一个对象,而指针本身就是一个对象,允许对指针赋值和拷贝,在生命周期内可以先后指向几个不同的对象。

引用必须初始化,指针无须在定义时赋初值,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。

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

#include<iostream>
int main()
{
	int i = 42;
	//p1是指向整型变量i的指针
	int* p1 = &i;
	//解引用p1得到i的值,将其平方后的值重新赋给i
	*p1 = *p1 * *p1;

	std::cout << i << std::endl;
}
//输出 1764

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

int main()
{
	int i = 0;
	double* dp = &i;	//试图把int型对象的地址赋给double型指针

	int* ip = i;		//不能把int变量直接赋给指针

	int* p = &i;		//合法
}

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

if (p)  //如果指针的值是0,条件的值为false,若是非0指针,条件的值为true

if (*p) //如果指针所指向的对象的值为0,条件的值为false,如果指针所指向的对象的值为非0,条件的值为true

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

不能,如果在定义指针时未初始化,p指向的地址未知。

应尽量等定义了对象之后再定义它的指针,也可以把指针初始化为nullptr或0。

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

int main()
{
	int i = 42;
	void* p = &i;
	long* lp = &i;
}

void*能存放任意类型对象的地址

lp是long类型的指针,不能存放int型对象的地址

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

int main()
{
	int* ip, i, & r = i;
	//ip是一个int型指针,i是一个int型变量,r是一个引用,与i绑定在一起

	int i, * ip = 0;
	//i是一个int型变量,ip是一个int型指针,值为0

	int* ip, ip2;
	//ip是一个int型指针,ip2是一个int型变量
}

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

int main()
{
	const int buf;		//不合法,const对象必须初始化

	int cnt = 0;		//合法

	const int sz = cnt;	//合法,cnt的值被拷贝给了sz

	++cnt;				//合法

	++sz;				//不合法,sz是一个const类型的对象,不能改变自身内容
}

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

int main()
{
	int i = -1, & r = 0;      //非法,r是一个非常量引用,初始值必须是一个对象

	int* const p2 = &i2;      //合法,p2是一个常量指针

	const int i = -1, & r = 0;//合法,i是一个int型常量,r是一个常量引用,允许绑定字面值0

	const int* const p3 = &i2;//合法,p3是一个指向常量对象的常量指针

	const int* p1 = &i2;      //合法,p1是一个指向常量对象的指针

	const int& const r2;      //非法,r2是一个常量引用,引用不是对象

	const int i2 = i, & r = i;//合法,i2是一个常量,r是一个常量引用,与i绑定
}

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

int main()
{
	int i, * const cp;		    //非法,i是整型变量,cp是一个常量指针,必须初始化

	int* p1, * const p2;		//非法,p1是一个指向int型的指针,p2是一个常量指针,必须初始化

	const int ic, & r = ic;		//非法,ic是一个未经初始化的常量,r是一个常量引用

	const int* const p3;		//非法,p3是一个指向常量对象的常量指针,必须初始化

	const int* p;				//合法,p是一个指向常量的指针
}

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

i = ic;          合法,把常量ic的值赋给i

p1 = p3;        非法,指向常量的指针不能赋值给普通指针

p1 = &ic;       非法,指向常量的指针不能赋值给普通指针

p3 = &ic;        非法,常量指针不能被赋值

p2 = p1;         非法,常量指针不能被赋值

ic = *p3;         非法,常量不能被赋值

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

int main()
{
	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,r2被声明成了底层const
	//p3被声明成了既有顶层const又有底层const
}

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

r1 = v2;        合法

p1 = p2;       非法,p2包含底层const的定义,但p1没有

p2 = p1;       合法,int*能转换成const int*

p1 = p3;       非法,p3包含底层const的定义,但p1没有

p2 = p3;       合法,p2和p3都是底层const

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

int main()
{
	int null = 0, * p = null;
	//非法:不能把int变量直接赋给指针

	//改为:
	int null = 0, * p = nullptr;
}

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

int main()
{
	int i = 0, & r = i;
	const int ci = i, & cr = ci;
	auto a = r;		//a是一个整数
	auto b = ci;	//b是一个整数
	auto c = cr;	//c是一个整数
	auto d = &i;	//d是一个整型指针
	auto e = &ci;	//e是一个指向整型常量的指针
	auto& g = ci;	//g是一个整型常量引用,绑定到ci
	a = 42;		//a=42
	b = 42;		//b=42
	c = 42;		//c=42
	d = 42;		//error
	e = 42;		//error
	g = 42;		//error
}

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

int main()
{
	const int i = 42;

	auto j = i;
	//j类型为int

	const 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:关于下面的代码,请指出每一个变量的类型以及程序结束时它们各自的值。

#include<iostream>
int main()
{
	int a = 3, b = 4;
	//a和b都是int

	decltype(a) c = a;
	//c是int

	decltype((b)) d = a;
	//d是int&

	++c;
	++d;
	std::cout << a << " " << b << " " << c << " " << d << std::endl;
}
//4 4 4 4

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

#include<iostream>
int main()
{
	int a = 3, b = 4;
	//a,b为int

	decltype(a) c = a;
	//c为int

	decltype(a = b) d = a;
	//d为int&
	std::cout << a << " " << b << " " << c << " " << d << std::endl;
}
// 3 4 3 3

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

类型说明符变量引用
auto忽略顶层const识别引用所指对象类型
decltype保留顶层const识别为引用类型

decltype的结果类型与表达式形式密切相关。

如果使用的是一个不加括号的变量,得到的结果是这个变量的类型。

如果使用的变量加上了一层或多层括号,编译器把它当作一个表达式,得到引用类型。

int main()
{
	int i = 0;
	const int ci = i, & cr = ci;

	auto a = i;				//a是一个int
	decltype (i) x = 0;		//x是一个int

	auto b = ci;			//b是一个int(ci的顶层const特性被忽略)
	decltype(ci) y = ci;	//y的类型是const int
}

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

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

2.40-2.42

编程题和第一章类似。

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值