C++ Primer(第五版)|练习题答案与解析(第二章:变量和基本类型)

C++ Primer(第五版)|练习题答案与解析(第二章:变量和基本类型)

本博客主要记录C++ Primer(第五版)中的练习题答案与解析。
参考:C++ Primer
C++ Primer

练习题2.1:

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

int、long、long long和short区别主要在可以表示的数据范围(尺寸)不同。
无符号数只能表示非负数,带符号的可以表示负数。
float为单精度浮点数,double为双精度,一般来说,float占4字节,double占8字节。执行浮点运算选用double,这是因为float通常精度不够而且双精度浮点数和单精度浮点数的代价相差无几。

练习题2.2

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

利率使用unsigned double,其精度更高,且为非负数。
本金和付款使用unsigned float,精度要求不那么高,且为非负数。

练习题2.3

读程序,写结果
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;

输出:

u2 - u:32
u - u2:4294967264 // -32的补码 4294967264
i2 - i:32
i - i2:-32
i - u:0
u - i:0

练习题2.5

(1)‘a’<字符字面值>, L’a’<宽字符字面值,类型是wchar_t>, “a”<字符串字面值>, L"a"<宽字符字符串字面值>
(2)10<十进制>, 10u<无符号整型>, 10L<长整型>, 10uL<无符号长整型>, 012<八进制>, 0xC<十六进制>
(3)3.14,<浮点数> 3.14f<单精度浮点型字面值,类型是float>, 3.14L<扩展精度浮点型字面值,类型是long double>
(4)10<十进制>, 10u<无符号整型>, 10.<浮点型>, 10e-2<浮点型字面值>

练习题2.6

int month = 9, day = 7;//定义的十进制数
int mouth = 09, dat = 07;//定义的八进制数,month会报错,因为已经超过8了。

练习题2.7

(1)“who goes with F\145rgus?\012”
输出who goes with Fergus?
这里使用的是转义序列,使用的Latin-1字符集,可查看 Latin-1\145 后面是8进制数,表示的是101(182+481+5*80),对应的是小写数字e
\012是换行符。
(2)3.14e1L
L是浮点型字面值的后缀。扩展的浮点型,类型是long double。
(3) 1024f
f是浮点型字面值的后缀。是单精度浮点型,类型是float。
(4) 3.14L
L是浮点型字面值的后缀。扩展的浮点型,类型是long double。

练习题2.8

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

测试

#include <iostream>
int main()
{
    std::cout << "\62\115\012" ;
    std::cout << "\62\t\115\012" ; 
    return 0;
}

输出:

2M
2       M

练习题2.9

(1)std::cin >> int input_value;
这个是错误的,不能在输入输出语句中定义变量。
(2) int i = { 3.14 };
错误,列表初始化且初始值存在丢失信息的风险,则编译器报错
(3) double salary = wage = 9999.99;
如果wage没有定义,则报错。
如果wage定义,则该语句可以正常执行,且wage和salary相等。
(4) int i = 3.14;
这个可以运行,会丢失数据,i倍转换为3。

练习题2.10

下面变量的初始值分别是多少。

测试:

#include <iostream>
std::string global_str;    //初始化为一个空串
int g_int;        // 初始化为0
int main()
{
    int local_int;      //按标准局部变量不初始化,g++编译器下可能也会初始化为空
    std::string local_str;
    std::cout<<"global_str:"<<global_str<<std::endl;
    std::cout<<"g_int:"<<g_int<<std::endl;
    std::cout<<"local_int:"<<local_int<<std::endl;
    std::cout<<"local_str:"<<local_str<<std::endl;

    return 0;
}

输出:

global_str:
g_int:0
local_int:0
local_str:

练习题2.11

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

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

练习题2.12

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

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

练习题2.13

下面程序中j的值是多少

测试:

#include <iostream>
int i =42;
int main()
{
    int i = 100;
    int j = i;
    std::cout << "j = " << j  << std::endl;       
    return 0;
}

输出:j = 100(使用局部变量j。)

练习题2.14

下面的程序合法吗?输出什么?

测试:

#include <iostream>
int main()
{
    int i =100, sum =0; 
    for (int i =0; i != 10; ++i) {
    sum += i;
    }   
    std::cout << i << " " << sum << std::endl; 
}

输出:100 45
for循环中的i,只在循环体内起作用,因此输出的是全局变量i= 100, 局部变量sum依旧在作用域内,因此输出局部变量sum=45。

练习题2.15

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

(1)int ival = 1.01;
编译是可以通过的,不过会丢失数据。
(2)int &rval1 = 1.01;
非法,引用类型的初始值必须是一个对象
(3)int &rval2 = ival;
合法的。
(4)int &rval3;
非法,引用必须初始化。

练习题2.16

哪些赋值是不合法的?为什么?哪些赋值是合法的?执行了什么样的操作?

int i = 0, &rl = i;
double d = 0, &r2 = d;

(a)r2 = 3.14159;
是合法的,d的值也变为3.14159
(b)r2 = r1;
是合法的,但隐式转化。r1是int型的引用,r2是double型的引用。关于这个可看C++ 隐式转换和显示转换
(c)i = r2;
是合法的,但同样含隐式转化。
(d)r1 = d;
是合法的,但同样含隐式转化。

练习题2.17

执行下面代码会输出什么结果?

#include <iostream>
int main()
{
    int i, &ri = i;
    i = 5;
    ri = 10; 
    std::cout << "i = " << i << "   ri = " << ri << std::endl;   
}

输出:i = 10 ri = 10
改变ri的值也会改变i的值

练习题2.18

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

测试代码:

#include <iostream>
int main()
{
    int i =20;
    int j = 10; 
    int* p = &i; 
    std::cout << "p = " << p << std::endl;    
    p = &j; 
    std::cout << "p = " << p << std::endl;    
    *p = 5;
    std::cout << "*p = " << *p << "  i = " << i  << "  j = " << j << std::endl;       
}

输出:

p = 0x61fe14
p = 0x61fe10
*p = 5  i = 20  j = 5

练习题2.19

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

  1. 引用在定义时必须初始化,而指针可不初始化。
  2. 引用在其生命周期内,只能指向一个对象,而指针可以先后指向不同的对象。
  3. 指针本身就是一个对象,允许对指针进行赋值和拷贝。

练习题2.20

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

int i = 42; 
int * p = &i; 
*p = *p * p;

赋值,计算42*42。

练习题2.21

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

int i = 0;

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

练习题2.22

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

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

练习题2.23

给定指针p,能否知道它指向了一个合法的对象?

不能。需要更多的信息才能知道指针是否有效。

练习题2.24

下面的代码中,为什么p合法而lp非法?

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

因为void指针类型可以存放任意对象的地址,但是long指针,就只能存放long对象的地址。

练习题2.25

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

(a) int* ip, i, &r = i;
ip 为int指针类型,i为int型,r为引用类型,初始化为i。
(b) int i, *p =0;
i为int型, p为int指针类型,初始化为0,并未指向任何对象。
© int* ip, ip2;
ip为int指针类型,ip2为int型。

练习题2.26

下面哪些句子是合法的,说明原因。

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

练习题2.27

下面哪些初始化是合法的,说明原因

(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; 是合法的。注意const int &r = 0 是正确的,引用是一个常量,但是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

下面哪些是合法的,请说明。

(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

假设已有上题中所定义的变量,则下面哪些是合法的?

(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。

(a)const int v2 = 0; int v1 = v2;
v2是顶层const
(b) int *p1 = &v1, &r1 = v1;
非const
(c) const int *p2 = &v2, *const p3 = &i, &r2 = v2;
p2是底层const,p3最左是底层,p3前面是顶层const, r2是底层const。

练习题2.31

假设已经有上题中的变量已定义,判断下面语句是否合法,说明原因。

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

练习题2.32

下面代码是否合法?如果不合法,请修改

int null = 0, *p = null;  

int *p是不能用int型来初始化。 应为int null = 0, *p = &null或者int *p = nullptr

练习题2.33

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

a = 42; b = 42; c = 42;       
d = 42; e = 42; g = 42;

其中, a, b, c的值均为42。d赋值错误,d是一个整型指针(int*)。e赋值错误,e是指向整数常量的指针(const int*)。g赋值错误,g是一个整型常量的引用,绑定到ci。

练习题2.34

基于上一题变量和语句编写程序,输出赋值前后的内容,判断推断是否正确

测试:

#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 << std::endl;     
    std::cout << b << std::endl;
    std::cout << c << std::endl;
    std::cout << d << std::endl;     
    std::cout << e << std::endl;
    std::cout << g << std::endl;

}

输出:

42
42
42
0x61fde4
0x61fde0
0

练习题2.35

判断下列定义推断出的类型什么,编程验证

测试:

#include <iostream>
int main()
{
    const int i = 42;       // i为const int类型
    std::cout<<"i:"<<i<<std::endl;
    auto j = i;             // j为int类型
    std::cout<<"j:"<<j<<std::endl;
    auto &k = i;            // k为const int& 类型
    std::cout<<"k:"<<k<<std::endl;
    auto p = &i;            // p为const int 类型
    std::cout<<"p:"<<p<<std::endl;
    const auto j2 = i, &k2 = i; // j2为const int类型,k2为const int& 类型。
    std::cout<<"j2:"<<j2<<std::endl;
    std::cout<<"k2:"<<k2<<std::endl;
}

输出:

i:42
j:42
k:42
p:0x61fdf4
j2:42
k2:42

练习题2.36

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

测试:

#include <iostream>
int main()
{
    int a = 3, b = 4;      
    decltype(a) c = a;     // c为int类型,a为c的初值
    std::cout<<"c:"<<c<<std::endl;
    decltype((b)) d = a;       // d为int& 类型,是a的引用
    std::cout<<"d:"<<d<<std::endl;
    ++c;               // ++c之后的值为4;
    std::cout<<"c:"<<c<<std::endl;
    ++d;               // ++d之后的值为4
    std::cout<<"d:"<<d<<std::endl;
}

输出:

c:3
d:3
c:4
d:4

练习题2.37

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

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

(1) a, b均为int
(2)c为int
(3)d为int&,是a的引用

练习题2.38

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

相同点:都通过已知变量或表达式的类型来指定类型。如:int i = 2; auto j = i; decltype(i) j = i; 两者相同。
不同点:(1)auto会忽略顶层const,但decltype不会。​ (2)auto定义变量必须有初始值,但decltyple不一定

int i = 0, &r = i;
// same
auto a = i;
decltype(i) b = i;
// different
auto c = r;
decltype(r) d = i;

练习题2.39

编译下面程序观察运行结果。

测试

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

输出:error: expected ';' after struct definition

练习题2.40

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

struct Sales_data
{
    string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};
发布了76 篇原创文章 · 获赞 44 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_24739717/article/details/102930797