C++ Primer (第五版) 课后习题 Unit2

2.1.1节练习:

练习2.1: 


 

这是在我自己电脑,64位机上跑的结果。字节不同,所以它们代表的范围也不同。所以这道题没有固定答案,其实还是要看使用的机器。

知道int是4个字节,所以就有 4*8=32 位 ,所以 可以知道unsigned int 范围是:0 - 2^32-1,而int 的范围是 -2^31 -- 2^31-1

其实short 和int 同理,2个字节,所以就是 2*8=16 位, 所以可知同理知道 unsigned int :0 - 2^16-1,short 范围 -2^15 -- 2^15 -1

我们根据之前的猜想,看看在电脑上执行的代码:

#include<iostream>
#include<limits.h>
using namespace std;
int main(){
    cout<<"基本数据类型范围\n";

    cout<<"char    :"<<numeric_limits<char>::min()<<'-'<<numeric_limits<char>::max()<<'\n';
    cout<<"short   :"<<numeric_limits<short>::min()<<'-'<<numeric_limits<short>::max()<<'\n';
    cout<<"int     :"<<numeric_limits<int>::min()<<'-'<<numeric_limits<int>::max()<<'\n';
    cout<<"unsigned int   :"<<numeric_limits<unsigned int>::min()<<'-'<<numeric_limits<unsigned int>::max()<<'\n';
    cout<<"long    :"<<numeric_limits<long>::min()<<'-'<<numeric_limits<long>::max()<<'\n';
    cout<<"long long   :"<<numeric_limits<long long>::min()<<'-'<<numeric_limits<long long>::max()<<'\n';
    cout<<"unsigned long long   :"<<numeric_limits<unsigned long long>::min()<<'-'<<numeric_limits<unsigned long long>::max()<<'\n';
    cout<<"float   :"<<numeric_limits<float>::min()<<'-'<<numeric_limits<float>::max()<<'\n';
    cout<<"double  :"<<numeric_limits<double>::min()<<'-'<<numeric_limits<double>::max()<<'\n';
    cout<<"long double   :"<<numeric_limits<long double>::min()<<'-'<<numeric_limits<long double>::max()<<'\n';
    return 0;
}

根据运行结果:

因为我的电脑上,long 和 long long 都是8个字节,所以没有什么差别。而且我们可以看到  long double 的精度到了惊人的 e+4932,看了long double 在电脑上的字节,16字节,好了,没有疑问了。

无符号和有符号的区别,还有long 和double 的区别在这张图上都显示出来了吧。

练习 2.2


计算按揭时,对于利率,因为一般不会到小数点38位以后,所以这里为了节省内存,选择float。

至于本金,很多人富可敌国,保险起见,还是选择 long double,因为我们不知道那一天通货膨胀到 一亿亿元买一瓶水,那还不得这个数。(逃,其实也用不到,,建议double

付款,也选择double 。通常付款=本金+本金*利率,double基本上都涵盖了。注意这里选择double 是基于本金选double的情况下。

 

练习2.3


2.1.3练习

练习2.5


a) 'a' 是字符;L'a'是宽字符类型,类型是wchar_t; "a"是字符串,里面只有一个字符'a'和'\0';L"a" 宽字符串

b)10,普通的int; 10u ,unsigned int ; 10L long ;10ul unsigned long,;012 八进制下的10;0xC 16进制的10

c)3.14,普通的double;3.14f float;3.14L long double 

d)10 int;10u unsigned int; 10. double; 10e-2  float (❌,这个是double类型,float类型必须有一个f,编译器会报错:expected unqualified-id)

练习2.6


day没有区别,但是month有,因为09是表示八进制的表示方法,而八进制的位上不应该出现比大于等于8的数,所以应该是无效的数字。

练习2.7


a)Who goes with Fergus? (一个换行) 字符串常量

b)31.4 long double 

c)1024 float (❌,虽然这个是后面有f,但是它数值本身是一个int数值)

d)3.14 long double 

练习2.8


cout<<2<<"\115\12";//这里用的都是八进制的数字,搜了半天好像这个转意符可以用16进制表示,但就是不能用10进制。

2.21节练习

练习2.9


a)不能在输入这里定义一个变量

b)会引发信息丢失,不能使用列表初始化

c)wage 没有定义,不可以直接使用。如果要同时定义wage和salary,就要分别让他们呢等于所要初始化的值。

d)没问题,但就是会丢失信息。

练习2.10


global_str 和 global_int 都是定义在函数体外面的,所以它们都被初始化位0

对于global_str =""

对于global_int=0

main中的变量被默认初始化,:

local_int : 不确定,因为它的值是未被定义的。

local_str:"" 它是string类,它的值由类决定,是空字符串。

2.22节练习

练习2.11


a)定义

b)定义

c)声明

2.23节练习

练习2.12


a)非法,double不能作为变量名

b)合法

c)catch 不能作为变量名

d)数字不能在变量名首部

e)合法

2.24节练习

练习2.13


j=100;

练习2.14


合法,输出100,45

2.3.1节练习

练习2.15


a)合法

b)不合法  不可以直接给引用赋值

c)合法

d)引用在定义时,就要对其初始化,所以不合法

练习2.16


a)合法,相当于给d赋值

b)引用的类型不同,不合法 ❌ --相当于将int的值赋给double,合法的

c)相当于将double的值赋值给int  合法

d)和c的操作相同,合法

练习2.17


输出:10 10

2.3.2节练习

练习2.18


#include <iostream>

int main() {
    double dval;
    double *pd = &dval;  //给指针赋一个地址值
    *pd = 2.333;//更改指针所指对象的值
    double aval;
    pd = &aval;//更改指针的值
    return 0;
}

练习2.19


指针:是有一个具体对象的,而且可以对指针的值进行修改

对象:没有一个具体对象,初始化时就要成为一个对象的别名。

练习2.20


计算i的平方,将计算结果再赋值给i.

练习2.21


a)指针类型必须和所指对象类型一致。不合法

b)初始化了一个指针 ip,但是却把一个int值赋给了它,而不是地址,不合法

c)合法

练习2.22


if(p) //看p是否是一个空指针

if(*p)//看p所指向的值是不是为0

练习2.23


只能通过输出指针的值,来判断指针是否为空指针,但是不能通过指针判断它是否指向了一个合法对象。

练习2.24


p是一个void * 指针,它可以存放任何类型对象的地址,但是lp 是long类型的指针,必须指向long的数据类型。

2.3.3节练习

练习2.25


a)ip是指向int类型的指针,i是一个int整型,r是一个对i的引用

b)i是一个整型,ip是一个指向int整型的空指针。

c)ip是一个指向int的指针,ip2是一个整型。

2.4节练习

练习2.26


a)不合法,const变量声明时必须赋上值

d)不合法,sz是一个cosnt变量,不能对其进行更改操作。

2.4.2节练习

练习2.27


a)不合法,非常量引用对象不能为常量。

b)常量指针,是合法的。前提是i2是一个指向int的对象。

c)常量引用,可以直接把常量给它, C++允许为一个常量引用绑定非常量的对象,比如字面值或者表达式。

d)常量指针指向int类型的常量,前提是i2 是一个指向int的对象

e)指向int 常量的指针,必须指向一个和指针类型相同的类型。这里前提是 i2是一个int类型

f)r2是一个对int常量引用的引用常量,因为引用本身就是不存在的,就不能让它作为常量。所以这个命名方式就是不对的(可以参考编译器报错情况),而且const对象一旦创建后,其值不再改变,所以const对象必须初始化。

g)将i的值赋给 i2,合法,允许为一个常量引用绑定非常量对象。

练习2.28


a)整型变量i ,指向int的常量指针cp。必须初始化,不合法

b)指向int的指针 p1,指向int的常量指针p2,必须初始化,所以不合法

c)不合法,定一个一个常量ic 必须要对其进行初始化,所以不合法

d)指向int常量的的常量指针 p3,所以不合法

e)指向int常量的指针 合法

练习2.29


a)合法,将常量赋值给一个非常量

b)将一个指向常量的常量指针赋给一个指向常量的指针,合法 

➕     不过 还有一个p1 是普通的指针,不能将指向常量的常量指针赋值给一个普通指针,因为指向常量指针默认不能通过该指针改变对象的值,因此也就不能将该指针赋值出去,让其他普通指针来改变它的值。

c)将常量的地址给一个非常量指针,不合法,因为不能通过指针来对常量进行修改

d)将一个int常量的地址赋给一个指向int常量的常量指针,合法

e)将一个指向int常量的指针赋给一个常量指针,不合法,因为不可以通过这个常量指针来对常量进行修改

➕    不过还有一个p1是普通的int指针,如果将一个普通的指向整型的指针赋给一个常量指针,是合法的。

f)将一个指向int常量的常量指针的值赋给了一个指针常量。合法

2.4.3节练习

练习2.30


a)const int v2 =0;//顶层cosnt     int v1 = v2;//不是一句合法声明❌  是合法的,这句相当于 int v1=0;顶层const 赋值对象是一个常量,等号右边的是一个顶层const

b) int *p1 = &v1,&r1 = v1; //既不是顶层,也不是底层,因为它不是常量

c)const int *p2 = &v2,*const p3 =&i,&r2 = v2;//p2是底层const,p3是顶层const 也是底层cosnt,普通的int *可以赋值给一个const int *, const int 的引用可以引用到const int,是一个底层const

练习2.31


r1 = v2;//不合法, 不能用int & 引用一个const int

p1=p2;//不合法,不能把底层const赋值给不是底层const的指针

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

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

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

2.4.4节练习

练习2.32


合法,指针p是空指针。

2.5.2节练习

练习2.33


一开始没理解这个题的意思,这个是说,把之前在程序用例中用auto生成的变量,集体赋值看看会怎么样:

a=42;//因为a本身就是一个整型,所以就是给整型赋值

b=42;//因为b本身也是一个整型(ci顶层的const特性被忽略了),所以也是整型赋值

c=42;//c也是一个整型,他是cr的引用,cr是ci的别称,所以其实这个和b类似,顶层的const也被忽略了。

d=42;//d是一个指向整型的指针,给指针赋值出错。不能把一个int 赋值给int*

e=42;//e是一个指向整数常量的指针,不能把一个int赋值给 const int *

g=42;//g是一个整数常量的引用,因为绑定的是常量,所以不能修改,程序会报错。错误原因是试图修改一个常量。

练习2.34


练习2.35


const int i =42;

auto j =i; //const 忽略, j是int 类型,值为42

const auto & k = i;//k是整型常量引用,绑定到i

auto *p = &i;//p是指向int常量的指针

const auto j2 =i,&k2 =i;//j2是一个int常量,值等于42   k2是整型常量引用,绑定到i,和k一样

2.5.3节练习

练习2.36


int a =3,b=4;

decltype(a) c =a; //c是一个int值,值为3

decltype((b)) d =a;//d是一个 int& ,int的引用,绑定到了a

++c;// c=4

++d;//d=a=4

练习2.37


int a=3,b=4;

decltype (a) c =a;//c是int类型,且大小等于a=3

decltype(a = b) d =a;//根据提示,赋值是会产生引用的表达式,且引用的类型就是左值,也就是int& 所以d是整型引用,绑定在a,是a的别名,大小=3

练习2.38


不同点1:decltype 指定类型,对引用会指定出来。而auto 则不是,它会适当改变结果,为了更符合初始化规则,所以可能会把引用的对象作为指定类型

int i =1,& m =i;

auto a = m;//这里a就为 m的对象,也就是i,所以a是int类型

decltype (m) a = i;//这里a就为i的另一个引用,是int&

不同点2:auto 会忽略顶层const,但是decltype不会忽略const

const int ci = 1;

auto b = ci;//b是一个整数,将const 忽略

decltype(ci)b =ci;//b是一个const int 类型的数,可以将ci赋给它

不同点3:decltype(())永远是引用,而auto不是

int a =3;

decltype((a)) b =a;  //b 为int& ,绑定到了a上

auto ((b)) =  a;//b 为 int

相同点:

int a =3;

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

auto b =a;//b 为int

2.6.1节练习

练习2.39


不加上分号,程序会报错。要求加上

练习2.40


struct Sales_data{

string bookNo;

double price;

string category;

int Sold;

};

练习2.40


#include <iostream>
#include<string> //这个string  还需要调用std空间
using  namespace std;

struct Sales_data{
    string bookNo;//书籍序号
    double price;//价格
    string category;//分类
    int Sold;//销量
};
void sum2Sales();
void sumPrice();
void printSal();
//void sumSold();
int main() {
    //读取两条编号相同的对象,并输出他们的和
    //读取多条有相同编号的对象,输出和,连续输入,如果监测到编号不同,则程序结束,打印结果
    //读取多条销售记录,统计每本书有几条销售记录,输出编号和销量,找到一个让程序结束的输入
    //输入多条销售记录,每个序号的记录应该聚在一起,找到一个让程序结束的输入
    cout<<"选择要计算的项目:0退出"<<endl;
    cout<<"1.读取两条编号相同的对象,并输出他们的和"<<endl;
    cout<<"2.读取多条有相同编号的对象,输出和(程序在监测到两次编号不同时结束)"<<endl;
    cout<<"3.读取多条销售记录,统计每本书有几条销售记录(输入EOF结束输入"<<endl;
//    cout<<"4.输入多条销售记录,每个序号的记录应该聚在一起(输入EOF结束输入"<<endl; //这条实际上与第三条同义
    int i;
    cin>> i;
    switch (i) {
        case 1:sum2Sales();
        break;
        case 2:sumPrice();
        break;
        case 3:printSal();
        break;
//        case 4:sumSold();
//        break;
        case 0:cout<<"退出!"<<endl;
        break;
        default:cout<<"输入错误,弹出!"<<endl;
        break;
    }
    return 0;
}
void sum2Sales(){
    Sales_data t1,t2;
    cout<<"请分别输入数据的编号,价格,分类,还有销量"<<endl;
    cout<<"请输入第一本的相关数据"<<endl;
    cin>>t1.bookNo>>t1.price>>t1.category>>t1.Sold;
    cout<<"请输入第二本的相关数据"<<endl;
    cin>>t2.bookNo>>t2.price>>t2.category>>t2.Sold;
    if(t1.bookNo == t2.bookNo) {
        cout << "两本书总共卖了:" << t1.Sold * t1.price + t2.Sold * t2.price << endl;
    }else{
        cout<<"两本书的编号不同!请确认"<<endl;
    }
}
void sumPrice(){
    Sales_data temp,native;
    double sum=0;
    cout<<"输入第一款产品及序列号,价格,分类,和销量:"<<endl;
    cin>>native.bookNo>>native.price>>native.category>>native.Sold;
    sum+=native.price*native.Sold;
    cout<<"再输入下一条产品的序列号,价格,分类,和销量"<<endl;
    while(cin>>temp.bookNo>>temp.price>>temp.category>>temp.Sold){
        if(temp.bookNo == native.bookNo){
            sum+=temp.price*temp.Sold;
            cout<<"再输入下一条产品的序列号,价格,分类,和销量"<<endl;
            continue;
        }else{
            cout<<"本次输入编号与之前不同,程序结束!之前产品的售价共为:"<<sum<<endl;
        }
    }
}
void printSal(){
    Sales_data temp1,temp2;
    cout<<"输入书籍序号, 价格,分类和销量"<<endl;
    cin>>temp1.bookNo>>temp1.price>>temp1.category>>temp1.Sold;
    double sum=0;
    sum+=temp1.price*temp1.Sold;
    cout<<"输入书籍序号, 价格,分类和销量"<<endl;
    while(cin>>temp2.bookNo>>temp2.price>>temp2.category>>temp2.Sold){
        if(temp1.bookNo == temp2.bookNo){
            sum+=temp2.price*temp2.Sold;
            cout<<"输入下一本书籍序号, 价格,分类和销量"<<endl;
            continue;
        }else{
            cout<<temp1.bookNo<<"的销售总额为"<<sum;
            sum=temp2.price*temp2.Sold;
            temp1.bookNo=temp2.bookNo;
            temp1.Sold=temp2.Sold;
            temp1.price=temp2.price;
            temp1.category = temp2.category;
            cout<<"输入下一本书籍序号, 价格,分类和销量"<<endl;
            continue;
        }
    }
    cout<<temp1.bookNo<<"的销售总额为"<<sum;
}

借鉴:https://github.com/applenob/Cpp_Primer_Practice/blob/master/excersize/ch02.md

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值