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