C++ Primer练习题(第二章)

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

它们的最小存储空间不同,分别为int(16位),long(32位),long long(64位),short(16位)。

无符号类型只能表示大于等于0的数。带符号类型可以表示正数,负数和0。

它们存储位数不同(float为32位,double为64位),因而取值范围不同,精度也不同(float精度为6位,double精度为10位)。

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

利率可以选择float 类型,因为利率通常为百分之几。一般只保留到小数点后两位,所以6 位有效数字就足以表示了。本金可以选择long 类型,因为本金通常为整数。long 类型可表示的最大整数一般为2^31-1(即2147483647),应该足以表示了。付款额一般为实数,可以选择double 类型,因为float 类型的6 位有效数字可能不足以表示。

练习2.3/2.4

#include 


using namespace std;


int main()

{

    unsigned u = 10, u2 = 42;

    cout << u2 - u << endl; //32

    cout << u - u2 << endl; //4294967264  -30%4294967296


    int i = 10, i2 = 42;

    cout << i2 - i << endl; //32

    cout << i - i2 << endl; //-32

    cout << i - u2 << endl; //4294967264 该行为自测多余

    std::cout << i - u << std::endl; //0

    cout << u - i << endl; //0

    return 0;

}
练习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) 'a' char类型, L'a' wchar类型, "a" 字符串类型, L"a"宽字符串类型

(b)10 int类型, 10u unsigned int类型, 10L long类型, 10uL unsigned long类型, 012 八进制表示的int类型,  0xC 十六进制表示的int类型

(c)3.14 double类型, 3.14f float类型, 3.14L double类型

(d)10 int类型, 10u unsigned int类型, 10. double类型, 10e-2 double类型

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

int month = 9, day = 7;

int month = 09, day = 07;

有区别,前者定义了month和day变量,值分别为9和7;后者定义了month和day变量,值分别为八进制的9(错误,编译器会报错)和7。 

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

 

(a)"Who goes with Fergus?\n" 类型是字符串类型

(b)31.4 类型是double

(c)1024 类型是float

(d)3.14 类型是double

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

#include 


using namespace std;


int main()

{

    cout << "\62\115\12";

    cout << "\62\t\115" <

练习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)(输入时才定义是不合法的)不正确,需在cin之前定义input_value

(b)会强转类型,编译器会报警告warning: narrowing conversion of '3.1400000000000001e+0' from 'double' to 'int' inside { } [-Wnarrowing]|

(c)wage未定义

(d)会强转类型,编译器不会报警告

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

std::string global_str;

int global_int;

int main()

{

    int local_int;

    std::string local_str;

}

global_strglobal_int 是全局变量,所以初值分别为空字符串和 0 。 local_int 是局部变量并且没有初始化,它的初值是未定义的。 local_str 是 string 类的对象,它的值由类确定,为空字符串。

 

注:如果在定义变量时没有指定初值,那么变量会被默认初始化。三条性质:1、定义在任何函数体外的变量会被初始化为0。 2、定义在函数体内部的变量不会被初始化。 3、类的对象未被初始化,则初值由类决定。

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

  • (a) extern int ix = 1024;
  • (b) int iy;
  • (c) extern int iz;

 

a 声明+定义

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 非法,与保留字重名

b 合法

c 非法,使用了非法字符

d 非法,以数字开头

e 合法

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

int i = 42;

int main()

{

    int i = 100;

    int j = i;

}

100 局部变量i覆盖了全局i。

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

int i = 100, sum = 0;

    for( int i = 0; i != 10; ++i)

        sum += i;

    std::cout<< i << ' ' << sum << std::endl;

合法,100 45。

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

  • (a) int ival = 1.01;
  • (b) int &rval1 = 1.01;
  • (c) int &rval2 = ival;
  • (d) int &rval3;

 

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合法,给d赋值为3.14159;b合法,给d赋值为i(会自动转换 int->double);c合法,给i赋值为d(会发生double->int,小数点后数据丢失);d合法,同c

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


int i, &ri = i;

i = 5; ri = 10;

std::cout << i << " " << ri << std::endl;

10 10

练习2.18 编写代码分别改变指针的值以及指针所指对象的值。

    int ival = 1024;

    int *p = &ival;

    int *p1 = nullptr;

    p1 = p;

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

1.引用是另一个对象的别名,而指针本身就是一个对象。

2.引用在定义时必须初始化,并且在其生命周期内只能绑定一个对象;指针不必在定义时初始化,也可以重新赋值使其指向其他对象。

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

int i = 42;

int *p1 = &i; 

*p1 = *p1 * *p1;

指针p1指向对象i,然后通过指针p1给对象i重新赋值为42*42(1764)

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

int i = 0;

(a) double* dp = &i;

(b) int *ip = i;

(c) int *p = &i;

a非法,double型指针指向了int型对象;b非法,不能将int型变量赋给指针;c合法

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


if (p) // ...

if (*p) // ...

1.判断指针p是否指向nullptr(空指针),是为false,否为true。2.判断指针p指向的变量的值是否为0

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

不能,判断指针是否指向了一个合法的对象首先需要知道指针的类型,还要知道指针指向的地址所存储的对象类型,并且还要知道指针指向的地址所存储的对象是否是所期望的对象。这几步在程序中极难做到,所以指针安全需要程序员正确使用指针。

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


int i = 42;

void *p = &i;

long *lp = &i;

指针p的类型为void* 他可以用于存放任何对象的地址。指针lp的类型为long,与变量i的类型int不符。

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

  • (a) int* ip, i, &r = i;
  • (b) int i, *ip = 0;
  • (c) int* ip, ip2;

a,ip为int型指针,i为int型对象,r为int型引用并与对象i绑定。b,i为int型对象,ip为int型空指针。c,ip为int型指针,ip2为int型对象。

练习2.26 下面哪些语句是合法的?如果不合法,请说明为什么?

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

int cnt = 0;        // 合法

const int sz = cnt; // 合法

++cnt; ++sz;        // 不合法, const 对象不能被改变

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

int i = -1, &r = 0;         // 不合法, r 必须引用一个对象

int *const p2 = &i2;        // 合法

const int i = -1, &r = 0;   // 合法

const int *const p3 = &i2;  // 合法

const int *p1 = &i2;        // 合法

const int &const r2;        // 不合法, r2未绑定一个常量对象或者常量

const int i2 = i, &r = i;   // 合法

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

int i, *const cp;       // 不合法, const 指针必须初始化

int *p1, *const p2;     // 不合法, const 指针必须初始化

const int ic, &r = ic;  // 不合法, const int 必须初始化

const int *const p3;    // 不合法, const 指针必须初始化

const int *p;           // 合法. 一个指针,指向 const int

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


i = ic;     // 合法, 常量赋值给普通变量

p1 = p3;    // 不合法, p3 是const int型指针不能赋值给int型指针

p1 = ⁣   // 不合法, int型指针不能指向const int型对象

p3 = ⁣   // 不合法, p3是一个常量指针,不能被再次赋值

p2 = p1;    // 不合法, p2是一个常量指针,不能被再次赋值

ic = *p3;   // 不合法, 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

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


r1 = v2; // 合法, 顶层const在拷贝时不受影响

p1 = p2; // 不合法, p2 是底层const,如果要拷贝必须要求 p1 也是底层const

p2 = p1; // 合法, int* 可以转换成const int*

p1 = p3; // 不合法, p3 是一个底层const,p1 不是

p2 = p3; // 合法, p2 和 p3 都是底层const,拷贝时忽略掉顶层const

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

int null = 0, *p = null;

非法,(error C2440: “初始化”: 无法从“int”转换为“int *”)可改为


int null = 0, *p = nullptr;

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

a=42; // a 是 int

b=42; // b 是一个 int,(ci的顶层const在拷贝时被忽略掉了)

c=42; // c 也是一个int

d=42; // d 是一个 int *,所以语句非法

e=42; // e 是一个 const int *, 所以语句非法

g=42; // g 是一个 const int 的引用,引用都是底层const,所以不能被赋值

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

#include 


int main()

{

    int i = 0, &r = i;

    auto a = r;   // a是一个整数(r是i的别名,而i是以一个整数)


    const int ci = i, &cr = ci;

    auto b = ci; // b是一个整数(ci的顶层const特性被忽略掉了)

    auto c = cr; // c是一个整数(cr是ci的别名,ci本身是一个顶层const)

    auto d = &i; // d是一个整型指针(整数的地址就是指向整数的指针)

    auto e = &ci; // e是一个指向整数常量的指针(对常量对象去地址是一种底层const)


    const auto f = ci; // ci的推演类型是int,f是const int

    auto &g = ci; // g是一个整型常量引用,绑定到ci


    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 << f << std::endl;

    std::cout << g << std::endl;

    std::cout << "--------------" << std::endl;

    a = 42; b = 42; c = 42; //d = 42; e = 42; g = 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 << f << std::endl;

    std::cout << g << std::endl;


    return 0;

}

练习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;

c为int型,d为int &。都为4。

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

int a = 3, b = 4;

decltype(a) c = a;

decltype(a = b) d = a;

c为int型,值为3;d为int &型,绑定到对象a上。

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

主要的区别有两点:

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

2:decltype(())双括号的差别。

decltype 处理顶层const和引用的方式与 auto不同,decltype会将顶层const和引用保留起来。


int i = 0, &r = i;

// same

auto a = i;

decltype(i) b = i;

// different

auto c = r;

decltype(r) d = i;

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

[Error] expected ';' after struct definition

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

struct Sales_data{

    std::string bookNo;

    std::string bookName;

    int num;

    double price = 0.0;

};

练习2.41 

练习2.42 

你可能感兴趣的:(C++ Primer练习题(第二章))