本门答案,部分参考于C++ Primer 习题集
第一章答案在这里:https://blog.csdn.net/Huangpengyu123/article/details/106605401
开头先放一张自己写的导图
① int,long,long long ,short 都属于整形,区别是C++标准规定的的尺寸的最小值,就是可以表示的最大的尺寸不同.
名字 | 长度 | 大小 |
---|---|---|
Short | 短整型 | 16 |
Int | 整形 | 16 |
long | 长整型 | 32 |
long long | 长整型 | 64 |
无符号的类型可以表示的数比有符号类型的数大.
Float和Double分别是单精度浮点数和双精度浮点数.
选择Double比较适合
Float精度不够,而且也省多少空间.
代码如下:
#include
int main(void) {
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;
return 0;
}
结果如下:
32
4294967264
32
-32
0
0
那个第二个结果是因为在我的环境里面,一个int是占32位的,最大是
4,294,967,295
官方资料如下:
https://docs.microsoft.com/zh-cn/cpp/cpp/data-type-ranges?view=vs-2019
地址.
其他都是好理解的.这里过.
如果有不理解的,可以评论问我
‘a’ 普通字符
L’a’ 宽字符型字面值,类型是wchar_t
“a” 普通字符串
L"a" 宽字符型字符串
10 int整形
10u unsigned
10L long
10uL unsigned long
012 8进制的数
0xC 16进制数
3.14 Double型
3.14f float型
3.14L long double 型
10 int
10u unsigned int
double
10e-2 科学计数法 表示为1
10 ∗ 1 0 − 2 10*10^{-2} 10∗10−2
不一样的,第一组定义的是10进制数.
第二组定义的是8进制数
而且 第二组的定义有错误,第二组定义了
int month=09;
而8进制最大而只有数字7
定义都是错误的
代码如下,我写了一个输出的代码
#include
#include
#include
using namespace std;
int main(void) {
string a;
a = "Who goes with F\145rgus?\012";
cout << a<
结果如下:
Who goes with Fergus?
31.4
3.14
是一个字符串,里面套了转义字符.
我们知道,没有加\x的转义字符,后面默认的就是8进制
所以\145就是1*8*8+4*8+5=101 在Ascii码表里面这个就是小写字母e
然后\012 就是1*8+2=10 表示换行.
3.14e1L 是一个科学计数法的长Double型
3.14 ∗ 1 0 1 3.14*10^{1} 3.14∗101
这个在我的编译器里会报错
要把1024f
改为1024.f
就是设置为浮点数
3.14L
就是设置为长double
#include
#include
#include
using namespace std;
int main(void) {
string a="";
a = "2M\n";
cout << a;
a = "2\tM\n";
cout << a;
return 0;
}
结果如下:
2M
2 M
错.
输入运算符的右侧需要一个明确的变量名称,而不是定义变量的语句
int input_value;
std::cin >> input_value;
错
这个是列表初始化,列表初始化不允许有初始值存在丢失信息的风险.编译器会报错
改正之后
int i = { 3 };
错
声明语句中声明多个变量时需要用逗号将变量名隔开,而不能使用赋值运算符连接.
改正后
#include
#include
int main(void) {
double salary, wage;
salary = wage = 9999.99;
return 0;
}
会报一个警告,但是不会报错.
改正后
int i = 3;
Global_int 是 0
local_int 在我的编译器里面不能编译.
其他的str都是0
定义了变量ix
声明并定义了变量iy
声明了变量iz
b 和 e是合法的
其他都是非法的
(a) double是C++里面的关键字
© -不可以作为变量名
(d) 变量名开头一定要是字母
j=100
因为
int j=i; //这里的i是main函数里面的i=100
合法
输出100,45
代码如下:
#include
#include
std::string global_str;
int global_int;
int main(void) {
int i = 100, sum = 0;
for (int i = 0; i != 10; ++i) {
sum += i;
}
std::cout << i << " " << sum << std::endl;
return 0;
}
输出100是因为i用的main函数里面的 i 而不是for里面的i
sum的值就是一个0–9的累加.
会有个警告,但是不会非法的
非法的
引用必须引用在一个对象上,而不能引用在某个表达式的值上,和字面值上。
合法
引用必须初始化,
合法的,实际上,就是把3.14159赋值给了d
合法,实际上,就是把i的值赋值给了d
合法,实际就是把d赋值给了i
进行了窄化操作
合法,实际就是把d赋值给了i
进行了窄化操作
完整可运行代码如下:
#include
#include
int main(void) {
int i, & ri = i;
i = 5, ri = 10;
std::cout << i << " " << ri << std::endl;
return 0;
}
结果是
10 10
因为引用就相当于一个别名,还是改变了i的值
测试代码如下:
#include
#include
int main(void) {
int i = 10, * p = &i,b=5;
//改变指针指向对象的值
std::cout << "P的值是:" << p << std::endl;
std::cout << "i的值是:" <
结果如下:
P的值是:004FFAA4
i的值是:10
P的值是:004FFAA4
i的值是:15
P的值是:004FFA8C
这题的答案参考于C++Prime的习题集(主要是他写的蛮好的,就借鉴了哈)
指针"指向"内存中的某个对象,而引用"绑定到"内存中的某个对象,它们都实现了对其他对象的间接访问,二者的区别主要有两方面:
① 指针本身就是一个对象,允许对指针的赋值和拷贝,而且在指针的生命周期内它可以指向几个不同的对象;引用不是一个对象,无法令引用重新绑定到另外一个对象.
② 指针无须再定义时赋初始值,和其他内置类型一样,再块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值;引用必须再定义的时候赋初值.
#include
#include
int main(void) {
int i = 42;
int* p1 = &i;
*p1 = *p1 * *p1; //*p1就代表i,相当于i=i*i
std::cout << i << std::endl;
return 0;
}
这段代码的意思,就是通过指针变量p1指向i
在通过p1来改变i的值.
非法
类型不匹配
double 类型的指针,不能指向int类型的变量
非法
不匹配,在指针指向的过程,需要&取地址符
合法
if§ //指的是判断p是不是一个无效指针,有没有指向任意一个对象.
if(*p) //指的是判断p所指向的那个对象的指等于不等于0
下面是测试的代码:
#include
#include
int main(void) {
int i = 42;
int* p1 = &i, * p2 = 0, * p3 = nullptr;
if (p1)
std::cout << "p1 is not null";
else
std::cout << "p1 is null";
std::cout << "\n";
if (p2)
std::cout << "p2 is not null";
else
std::cout << "p2 is null";
std::cout << "\n";
if (p3)
std::cout << "p3 is not null";
else
std::cout << "p3 is null";
std::cout << "\n";
return 0;
}
结果如下:
p1 is not null
p2 is null
p3 is null
void 类型的指针可以存放任意类型的地址.
long类型和int类型不匹配
int* ip, i, & r = i;
*ip是一个int类型的指针
它如果是一个全局变量,那么它就是为空
如果它在快作用域里面,它的值就是不确定的
i 就是一个普通的int类型的变量
全局为空
快作用域不确定
r是i的一个引用
r跟着i走走,i是什么,它是什么.
int i, * ip = 0;
i 就是一个普通的int类型的变量
全局为空
快作用域不确定
ip 是一个int类型的空指针
int* ip, ip2;
ip2 就是一个普通的int类型的变量
全局为空
快作用域不确定
*ip是一个int类型的指针
它如果是一个全局变量,那么它就是为空
如果它在快作用域里面,它的值就是不确定的
非法的
const类型必须初始化
合法的
合法的,可以用int类型来初始化const int对象
非法的
++cnt是合法的
++sz是非法的
sz是const类型,const类型不能改变它的值.
是非法的,非常亮引用 r 不能引用字面值常量0
是合法的,p2是一个常量指针,p2的值永不改变,即p2永远指向变量i2
是合法的,i是一个常量,r是一个常量引用,此时r可以绑定倒字面值常量0中
是合法的,p3是一个常量指针,p3的值永不改变,即p3永远指向变量i2,同时p3指向的是常量,即我们不能通过p3改变所指对象的值.
是合法的,p1指向一个常量,即我们不能通过p1改变所指对象的值
是非法的,引用本身不是对象,因此不能让引用恒定不变
是合法的,i2是一个常量,r是一个常量引用
int *const cp
const 指针必须初始化
int *p1,*const p2
const指针必须初始化
const 常量必须要初始化 ic
const int *const p3;
p3是一个常量指针,指向的对象是一个int类型的常量
常量指针必须要初始化,所以错误
不合法
合法,但是p没有指向任何实际的对象
合法的
非法的
普通指针p1指向了一个常量
而且,普通指针p1的值可以任意的改变,这与实际不符
非法
普通指针p1指向了一个常量
普通指针p1的值可以任意的改变,这与实际不符
非法
p3只能再定义的时候,被初始化,后来就不可以改变p3的指向了
非法的
p2是一个常量指针,只能再定义的时候,被初始化,后来就不可以改变p2的指向了
非法的
ic只能再定义的时候,被初始化
v2和p3是顶层const,分别表示一个整形常量和一个整形常量指针
p2和r2是底层const,分别表示它们所指(所引用的对象是常量)
r1 = v2; //r1是一个普通引用,可以通过v2来改变r1的值,实际上,就相当与把v2的值,赋值给了v1
p1 = p2; //非法的,p1是一个普通指针,p2是一个指向常量的指针
//p2是一个指向常量的指针,p1=p2的指向,会引起冲突
p2 = p1; //合法的,p1是一个普通指针,p2是一个指向常量的指针
//p2是一个指向常量的指针
//p2不会改变p1指向的对象的内容
p1 = p3; //合法的,p1是一个普通指针
//p3是一个常量指针,指向的是一个常量对象
//p1=p3
//p1可能会修改p3指向的对象的值,会引起冲突
p3 = p1; //合法的,p1是一个普通指针
//p3是一个常量指针,指向的是一个常量对象
//p3=p1
//p3不可能修改p1指向的对象的值,不会引起冲突
错误
指针不可以直接绑定一个int类型
根据题意,可以修改为
int null = 0, * p = nullptr;
前三条语句都是正确的,因为a,b,c都是整数
后三条都不太正确.
d,e都是指针,这样肯定是错误的.
g是一个整型常量引用,他是不可以改变引用的对象的.
#include
#include
int main(void) {
int i = 0, & r = i; //一个普通整形,和一个普通整形引用
auto a = r; //这个a是int型的(r是i的别名,i还是一个整数)
const int ci = i, & cr = ci; //这个ci就是整形常量,cr是整形常量引用
auto b = ci; //b还是一个整数(ci的顶层const属性被忽视掉了--因为ci是一个常量,所以它拥有顶层const属性)
auto c = cr; //c还是一个整数(cr是ci的别名),ci的顶层const属性一样被忽略掉了
auto d = &i; //d是一个整形指针,好理解
auto e = &ci; //e是一个指向整数常量的指针(对常量对象取地址是一种底层的const)
//对指针来讲,对常量取地址就是底层的const
const auto f = ci; //ci推出来还是int类型,但是f是const int就是整形常量
auto& g = ci; //g是一个整形常量引用,绑定到ci
//auto类型在进行引用的时候,对象的顶层属性依然被保留
std::cout << a << ":" << b << ":" << c << ":" << d << ":" << e << ":" << g << std::endl;
//auto& h = 42; //引用不能绑定常量
const auto& j = 42; //f是一个整形常量引用,可以绑定到字面值
auto k = ci, & l = i; //k是一个int,l是一个整形引用 这里auto的类型是int型
auto& m = ci, * p = &ci; //m是一个整形常量引用,p是一个指向整型常量的指针 这里auto的类型是const int型
//auto& n = i, * p2 = &ci; //这里的话,前面的&n是一个int类型的引用,
//后面的*p2又是一个const int 类型的指针,两个类型冲突,所以报错
a = 42; //a是int类型,不影响r,和i
std::cout << r << ":" << i << std::endl;
b = 42; //b也是同理
std::cout << cr << ":" << ci << std::endl;
c = 42; //c也是同理
std::cout << cr << ":" << ci << std::endl;
//d = 42;
//e = 42;
//g = 42;
std::cout << a << ":" << b << ":" << c << ":" << d << ":" << e << ":" << g << std::endl;
return 0;
}
这个是我自己写的验证程序
#include
#include
int main(void) {
const int i = 42; //整形常量
auto j = i; //j就是一个普通的int类型
const auto& k = i; //一个整形常量引用
auto* p = &i; //一个整形常量指针
const auto j2 = i, & k2 = i; //整形常量j2,整形常量引用k2
//i = 43; //报错
j = 10; //可以修改
//k = 10; //对const的引用,不允许通过k来修改i的值
int a = 10;
p = &a; //这样是可以的,而且a的值,自己还可以改变
//*p = 42; //p是一个指向常量的指针,不允许通过p来修改它指向的对象
//但是p指向的对象可以自己修改自己的值PS,如果它可以的话
a = 42;
//j2 = 10; //报错
//k2 = 10; //报错
return 0;
}
#include
#include
int main(void) {
const int i = 42;
auto j = i;
const auto& k = i;
auto* p = &i;
const auto j2 = i, & k2 = i;
std::cout << typeid(i).name() << std::endl;
std::cout << typeid(j).name() << std::endl;
std::cout << typeid(k).name() << std::endl;
std::cout << typeid(p).name() << std::endl;
std::cout << typeid(j2).name() << std::endl;
std::cout << typeid(k2).name() << std::endl;
return 0;
}
运行结果如下:
我的环境是VS2019
int
int
int
int const *
int
int
#include
#include
int main(void) {
int a = 3, b = 4;
decltype(a) c = a; //int 类型的c
decltype((b)) d = a; //d是a的引用.
++c;
++d; //++d相对于++a
std::cout << a << ":" << b << ":" << c << ":" << d << std::endl;
return 0;
}
这题我套用了上一题的代码
#include
#include
int main(void) {
int a = 3, b = 4;
decltype(a) c = a; //int 类型的c
decltype(a=b) d = a; //d是a的引用.因为(a=b)这个整体是一个表达式,decltype里面对表达式的类型
//判断就是为引用.
++c;
++d; //++d相对于++a
std::cout << a << ":" << b << ":" << c << ":" << d << std::endl;
return 0;
}
这题答案,是我参考的
① auto类型说明符用编译器计算变量的初始值来推断其类型,而decltype虽然也让编译器分析表达式并得到它的类型,但是不计算表达式的值
② 编译器推断出来的auto类型有时候和初始值的类型并不完全一样,编译器会适当的改变结果类型使其更符合初始化的规则
例如:auto一般会忽略顶层const,而把底层的const保留下来,与之相反,decltype会保留变量的顶层const
③ 与auto不同,decltype的结果类型与表达式形式密切相关,如果变量名加了一对括号,则得到的类型与不加括号时会有不同.如果deltype使用的是一个不加括号的变量,则得到的结果就是改变量的类型;如果给变量加上了一层或多层括号,则编译器将推断得到引用类型
下面是一个例子
#include
#include
int main(void) {
int a = 3; //int
auto c1 = a; //int
decltype(a) c2 = a; //int
decltype((a)) c3 = a; //int 引用
const int d = 5; //const int
auto f1 = d; //int
decltype(d) f2 = d; //整型常量
std::cout << typeid(c1).name() << std::endl;
std::cout << typeid(c2).name() << std::endl;
std::cout << typeid(c3).name() << std::endl;
std::cout << typeid(f1).name() << std::endl;
std::cout << typeid(f2).name() << std::endl;
c1++;
c2++;
c3++; //因为c3是a的引用,实际就相当与自增a了
f1++;
//f2++; //因为是整形常量,所以不能自增
std::cout << a << ":" << c1 << ":" << c2 << ":" << c3 << ":" << f1 << ":" << f2 << std::endl;
return 0;
}
struct Sales_data {
std::string bookNo; //书籍编号
unsigned units_sold = 0; //销售量
double sellingprice = 0.0; //零售价
double saleprice = 0.0; //实售价
double discount = 0.0; //折扣
};
如果这篇文章对你有张帮助的话,可以用你高贵的小手给我点一个免费的赞吗
相信我,你也能变成光.
如果你有任何建议,或者是发现了我的错误,欢迎评论留言指出.