参考书目:c++ primer第五版,c++ primer习题集
练习2.1
int、long、long long 和short的不同点在于在内存中尺寸不同,即表示的整数的范围不同。c++标准规定每种尺寸的最小值:short占16位,int占16位,long为32位,long long为64位。
无符号类型只能表示0和正数,32位的无符号类型整数能表示 [ 0 , 2 32 − 1 ] [0, 2^{32}-1] [0,232−1]的范围,而32为带符号整数能表示 [ − 2 31 , 2 31 − 1 ] [-2^{31} , 2^{31}-1] [−231,231−1]的范围
float和double的区别在于在内存中的长度不同,主要体现在double能表示的精度比float高,且表示的最大最小数大于float
练习 2.2
首先要采用浮点数表示,我会用double
练习2.3
第一个cout语句,执行结果正确,42-10=32
第二个cout语句,10-42=-32,而由于两个数都是无符号整数,发生溢出,结果为
−
32
+
2
32
=
4294967264
-32+2^{32}=4294967264
−32+232=4294967264 (我的int占32位,这也说明了练习2.1中,c++规定了int最少占16位,但是没有规定一定是16位)
第三个cout,两个有符号整数运算,结果是有符号的,为32
第四个cout,同理,10-42=-32,没有问题
第五个cout,有符号数与无符号数做运算,编译器先把有符号数转化为无符号整数,10还是10,10-10=0,没有溢出
第六个cout 同理
练习 2.5
考察的是这个表,注意对于字符和字符串是前缀,对于浮点数和整数是后缀
(a)第一个是字符a。第二个是宽字符型字面值 a, 第三个是字符串a,第四个是宽字符型字符串a
(b)10是整数字面值,10u是无符号数,10L是长整型,10uL是无符号长整数,012是八进制12,其十进制是10,0xC是十六进制数,十进制是12
注意后缀指出的是最小匹配类型,由于这里的数比较小,不用考虑容纳不下的情况
(c ) 3.14默认使用double存储,3.14f是float, 3.14L是long double
(d) 10是整数,10u是无符号整数,10. 是浮点数,10e-2是浮点数0.1
练习2.6
第一行是10进制的int
第二行是八进制的int,其中month=09会报错
练习2.7
(a)???真的有人这样表示吗?转义字符“\”后面可以加三位八进制的ASCII码,注意是八进制,\145是e \120是换行符
(b)long double的31.4,
(c)1024的float
(d)long double的3.14
练习2.8
#include<iostream>
using namespace std;
int main(){
cout<<"2M\n";
cout<<"2\tM\n";
return 0;
}
练习2.9
使用dev c++编译
(a)[Error] expected primary-expression before ‘int’
正确做法,先定义变量,再cin
int input_value;
std::cin>>input_value;
(b)得到整型 i=3
(c)[Error] ‘wage’ was not declared in this scope
正确做法,先定义,再赋值
double salary,wage;
salary=wage=999.99;
(d)得到整型 i=3
练习2.10
这三句话:
- 定义于任何函数体之外的变量被初始化为0
- 定义在函数体内部的内置类型变量将不被初始化
- 类的对象如果没有显式地初始化,则其值由类确定。
所以,global_str和local_str为空字符串,global_int=0,local_int 未定义。
练习2.11
(a)定义变量 ix,注意不能放在函数内部,否则报错
(b)声明并定义iy
©声明iy但不定义
练习2.12
不能用关键字为名称,只能包含下划线、数字、字母,不能以数字开头
正确:(b) (e) ,其他错误
练习2.13
j=100,局部变量覆盖全局变量
练习2.14
输出100和45,注意循环内的i和循环外的i是不一样的
练习2.15
(a)合法,得到ival=1
(b)不合法,引用不能绑定字面值,改为const & rval1=1.01可以
(c)合法
(d)不合法,引用必须初始化
练习2.16
(a)合法,相当于把变量d的值变为3.14159
(b)合法,相当于把 i 赋值给d
(c)合法,相当于把 d 赋值给 i
(d)合法,同(c)
练习2.17
都输出10,分析过程可以直接把 ri 换成 i 来看
练习2.18
int main(){
int i=1,j=2;
int* p=&i;
p=&j //改变指针本身的值
*p=100;//改变指针所指对象(j)的值
return 0;
}
练习2.19
指针本身是内存中的对象,而引用不是对象
指针可以指向不同的其他对象,而引用一经绑定不能再改变所绑定的对象
指针可以在定义时不初始化,但是引用必须在定义时初始化
练习2.20
计算42的平方
练习2.21
(a)不合法,指针的类型必须和变量的类型匹配。
(b)非法,不能直接把int赋值给int*
(c)合法
练习2.22
检测指针p是否为空指针
检测p指向的int是否为0
练习2.23
在某些情况下,我们能知道指针没有执行一个合法的对象,比如指针为0,指针指向了禁止访问的区域,程序报错。但是反过来并不能说明指针指向的合法的内存。例如在dev c++编译运行下面的代码:
int main(){
int i=0;
int* pi=&i;
cout<<*(p+10);
return 0;}
并没有报错,但是输出了未定义的值
练习2.24
p合法是因为void* 指针可以指向任意类型的变量,而long* 的指针只能指向long型的变量
练习2.25
(a)ip是int 型指针,i是int型变量,r 是 int型的引用,且绑定了变量i
(b)i是int 型变量,ip是int型指针且被初始化为0
(c)ip是int型指针,ip2是int型变量
练习2.26
(a)非法,const变量和引用类似,必须初始化
(b)合法
(c)合法
(d)非法,对于cnt可以自增,但是sz是const变量,不能自增
练习2.27
(a)非法,引用 r 必须绑定对象而不是绑定字面值
(b)合法
(c)合法,const引用可以绑定字面值
(d)合法
(e)合法
(f)非法,引用本身就不能改变绑定的对象,没有所谓 int &const r2
(答案是:引用本身不是对象,不能让引用恒定不变)
(g)合法
练习2.28
(a)定义一个int型变量和一个指向int的常量指针,非法,cp没有初始化
(b)定义一个指向int的指针p1和指向int的常量指针p2,非法,p2没有初始化
(c)定义int常量ic和const引用r,非法,ic没有初始化
(d)定义一个指向int常量的常量指针,非法,p3没有初始化
(e)定义了一个指向int常量的指针,合法,他可以不初始化。同时,const决定我们不能通过p3改变其指向的值,但是不要求 p 必须指向const int类型的变量。
练习2.29
(a)合法 i 是int,可以改变值
(b)合法,p1和p3都指向int,且p1不是常量指针
p1是普通指针,而p3是指向常量的指针,如果合法,那么可以通过p1更改p3指向内容,逻辑说不过去
(c)不合法,ic是个常量,p1是普通指针
(d)合法,ic是常量,p3是指向常量的指针,相匹配
非法,常量指针不能赋值
(e)非法,常量指针不能赋值
(f)非法,常量不能被赋值
总结:这个题错的有点离谱,总结一下:
- 要考虑赋值运算符左边的对象的顶层const,即本身能不能赋值
- 考虑底层的const,有const可以指向没const的,没const不能指向const
- 要考虑类型匹配(这里没有这个问题)
练习2.30
v2是顶层const
p2是底层const
p3是顶层const和底层const
r2是底层cosnt
练习2.31
第一个语句是合法的,首先r1没有底层const,所以可以直接赋值,v2是被拷贝的对象,他虽然自身有顶层const但是不受影响。最终结果将改变变量v1的值。
第二行第一个是非法,p2有底层const,p1没有,p1在左,p2在右,非法操作;
第二行第二个,反过来是可以的,首先考虑p2没有顶层const,可以赋值。其次p2有底层const,p1没有,p2在左边,没问题
第三个第一个,非法,左边没有底层const,右边有底层const,非法
第三行第二个,合法,首先p2没有顶层const,可以赋值。左右两边都有底层const,没有问题。类型匹配
练习2.32
空指针应该被初始化为nullptr,而不是整型数字0,这两者是有区别的。
练习2.33
a的值变为42
b的值变为42
c的值变为42
d报错,d是个指针,不能直接用整数赋值
e是个指向常量的指针,不能用整数赋值
g绑定了ci,ci是个常量,不能赋值
练习2.34
练习2.35
j是一个普通的int变量,因为auto不会保留顶层const
k会是一个与int变量绑定的const引用
p是指向整型常量的指针,因为auto会保留底层const
j2是个整数常量,因为定义的时候显示指明了const,k2是整数常量引用 (习题册可能想说auto 推出的是int?)
实验1:改变 j 的值,不影响 i 和 k 的值——证明 j 是一个独立的int变量
实验2:对i,k,k2 取地址,两者地址相同;对i k赋值,编译报错
参考书代码关键点:typeid().name(),用于获得表达式的类型,以c-style字符串形式返回类型名。
搞不懂对于const int i=42,为什么调用上面的函数输出的是int?
练习2.36
a是一个整型
b是一个整型
c是一个整型
d是一个引用且绑定了a
结束后
a=4,b=4,c=4,d=4
练习 2.37
a是int,b是int,c是int,d是int的引用
a,b,c,d 3,4,3,4
因为第三行 a=b 并不会被真正执行
练习2.38
- 对于引用,auto使用的是引用绑定的对象“本尊”,decltype会保留引用类型
- 对于const,auto会忽略顶层const保留底层const,而decltype会同时保留顶层const和底层const
- 对于括号,decltype给变量名加上一对括号会得到引用类型,不加括号是该变量的类型
推断出来的结果一样:
int main(){
int i=42;
auto ai=i;
decltype(i) bi=i;
}
上述代码推断的ai和bi都是int
推断出来结果不同:
int main(){
const int i=42;
auto ai=i;
decltype(i) bi=i;
}
对于ai,由于auto忽略顶层const,其类型是int;而decltype会保留顶层const,类型是const int
练习2.39
报错信息:[Error] expected ‘;’ after struct definition
练习2.40
后面的编程题应该自己发挥就好了
总结
判断表达式正确和错误
- 要考虑赋值运算符左边的对象的顶层const,即本身能不能赋值
- 考虑底层的const,有const可以指向没const的,没const不能指向const
- 要考虑类型匹配(这里没有这个问题)
auto与decltype
- 对于引用,auto使用的是引用绑定的对象“本尊”,decltype会保留引用类型
- 对于const,auto会忽略顶层const保留底层const,而decltype会同时保留顶层const和底层const
- 对于括号,decltype给变量名加上一对括号会得到引用类型,不加括号是该变量的类型
- decltype只判断表达式的类型,不会执行表达式