本門答案,部分參考於C++ Primer 習題集
第一章答案在這裏:https://blog.csdn.net/Huangpengyu123/article/details/106605401
開頭先放一張自己寫的導圖
文章目錄
2.1
① int,long,long long ,short 都屬於整形,區別是C++標準規定的的尺寸的最小值,就是可以表示的最大的尺寸不同.
名字 | 長度 | 大小 |
---|---|---|
Short | 短整型 | 16 |
Int | 整形 | 16 |
long | 長整型 | 32 |
long long | 長整型 | 64 |
無符號的類型可以表示的數比有符號類型的數大.
Float和Double分別是單精度浮點數和雙精度浮點數.
2.2
選擇Double比較適合
Float精度不夠,而且也省多少空間.
2.3+2.4
代碼如下:
#include<iostream>
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
地址.
其他都是好理解的.這裏過.
如果有不理解的,可以評論問我
2.5
(a)
‘a’ 普通字符
L’a’ 寬字符型字面值,類型是wchar_t
“a” 普通字符串
L"a" 寬字符型字符串
(b)
10 int整形
10u unsigned
10L long
10uL unsigned long
012 8進制的數
0xC 16進制數
©
3.14 Double型
3.14f float型
3.14L long double 型
(d)
10 int
10u unsigned int
-
double
10e-2 科學計數法 表示爲1
2.6
不一樣的,第一組定義的是10進制數.
第二組定義的是8進制數
而且 第二組的定義有錯誤,第二組定義了
int month=09;
而8進制最大而只有數字7
定義都是錯誤的
2.7
代碼如下,我寫了一個輸出的代碼
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main(void) {
string a;
a = "Who goes with F\145rgus?\012";
cout << a<<endl;
cout << 3.14e1L << endl;
//cout << 1024f; //在我的VS2019中,編譯會報錯.
cout << 3.14L << endl;
return 0;
}
結果如下:
Who goes with Fergus?
31.4
3.14
(a)
是一個字符串,裏面套了轉義字符.
我們知道,沒有加\x的轉義字符,後面默認的就是8進制
所以\145就是1*8*8+4*8+5=101 在Ascii碼錶裏面這個就是小寫字母e
然後\012 就是1*8+2=10 表示換行.
(b)
3.14e1L 是一個科學計數法的長Double型
©
這個在我的編譯器裏會報錯
要把1024f
改爲1024.f
就是設置爲浮點數
(d)
3.14L
就是設置爲長double
2.8
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main(void) {
string a="";
a = "2M\n";
cout << a;
a = "2\tM\n";
cout << a;
return 0;
}
結果如下:
2M
2 M
2.9
(a)
錯.
輸入運算符的右側需要一個明確的變量名稱,而不是定義變量的語句
int input_value;
std::cin >> input_value;
(b)
錯
這個是列表初始化,列表初始化不允許有初始值存在丟失信息的風險.編譯器會報錯
改正之後
int i = { 3 };
©
錯
聲明語句中聲明多個變量時需要用逗號將變量名隔開,而不能使用賦值運算符連接.
改正後
#include<iostream>
#include<string>
int main(void) {
double salary, wage;
salary = wage = 9999.99;
return 0;
}
(d)
會報一個警告,但是不會報錯.
改正後
int i = 3;
2.10
Global_int 是 0
local_int 在我的編譯器裏面不能編譯.
其他的str都是0
2.11
(a)
定義了變量ix
(b)
聲明並定義了變量iy
©
聲明瞭變量iz
2.12
b 和 e是合法的
其他都是非法的
(a) double是C++裏面的關鍵字
© -不可以作爲變量名
(d) 變量名開頭一定要是字母
2.13
j=100
因爲
int j=i; //這裏的i是main函數裏面的i=100
2.14
合法
輸出100,45
代碼如下:
#include<iostream>
#include<string>
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的累加.
2.15
(a)
會有個警告,但是不會非法的
(b)
非法的
引用必須引用在一個對象上,而不能引用在某個表達式的值上,和字面值上。
©
合法
(d)
引用必須初始化,
2.16
(a)
合法的,實際上,就是把3.14159賦值給了d
(b)
合法,實際上,就是把i的值賦值給了d
©
合法,實際就是把d賦值給了i
進行了窄化操作
(d)
合法,實際就是把d賦值給了i
進行了窄化操作
2.17
完整可運行代碼如下:
#include<iostream>
#include<string>
int main(void) {
int i, & ri = i;
i = 5, ri = 10;
std::cout << i << " " << ri << std::endl;
return 0;
}
結果是
10 10
因爲引用就相當於一個別名,還是改變了i的值
2.18
測試代碼如下:
#include<iostream>
#include<string>
int main(void) {
int i = 10, * p = &i,b=5;
//改變指針指向對象的值
std::cout << "P的值是:" << p << std::endl;
std::cout << "i的值是:" <<i << std::endl;
*p = 15;
std::cout << "P的值是:" << p << std::endl;
std::cout << "i的值是:" << i << std::endl;
//改變指針的值
p = &b;
std::cout << "P的值是:" << p << std::endl;
return 0;
}
結果如下:
P的值是:004FFAA4
i的值是:10
P的值是:004FFAA4
i的值是:15
P的值是:004FFA8C
2.19
這題的答案參考於C++Prime的習題集(主要是他寫的蠻好的,就借鑑了哈)
指針"指向"內存中的某個對象,而引用"綁定到"內存中的某個對象,它們都實現了對其他對象的間接訪問,二者的區別主要有兩方面:
① 指針本身就是一個對象,允許對指針的賦值和拷貝,而且在指針的生命週期內它可以指向幾個不同的對象;引用不是一個對象,無法令引用重新綁定到另外一個對象.
② 指針無須再定義時賦初始值,和其他內置類型一樣,再塊作用域內定義的指針如果沒有被初始化,也將擁有一個不確定的值;引用必須再定義的時候賦初值.
2.20
#include<iostream>
#include<string>
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的值.
2.21
(a)
非法
類型不匹配
double 類型的指針,不能指向int類型的變量
(b)
非法
不匹配,在指針指向的過程,需要&取地址符
©
合法
2.22+2.23
if§ //指的是判斷p是不是一個無效指針,有沒有指向任意一個對象.
if(*p) //指的是判斷p所指向的那個對象的指等於不等於0
下面是測試的代碼:
#include<iostream>
#include<string>
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
2.24
void 類型的指針可以存放任意類型的地址.
long類型和int類型不匹配
2.25
(a)
int* ip, i, & r = i;
*ip是一個int類型的指針
它如果是一個全局變量,那麼它就是爲空
如果它在快作用域裏面,它的值就是不確定的
i 就是一個普通的int類型的變量
全局爲空
快作用域不確定
r是i的一個引用
r跟着i走走,i是什麼,它是什麼.
(b)
int i, * ip = 0;
i 就是一個普通的int類型的變量
全局爲空
快作用域不確定
ip 是一個int類型的空指針
©
int* ip, ip2;
ip2 就是一個普通的int類型的變量
全局爲空
快作用域不確定
*ip是一個int類型的指針
它如果是一個全局變量,那麼它就是爲空
如果它在快作用域裏面,它的值就是不確定的
2.26
(a)
非法的
const類型必須初始化
(b)
合法的
©
合法的,可以用int類型來初始化const int對象
(d)
非法的
++cnt是合法的
++sz是非法的
sz是const類型,const類型不能改變它的值.
2.27
(a)
是非法的,非常亮引用 r 不能引用字面值常量0
(b)
是合法的,p2是一個常量指針,p2的值永不改變,即p2永遠指向變量i2
©
是合法的,i是一個常量,r是一個常量引用,此時r可以綁定倒字面值常量0中
(d)
是合法的,p3是一個常量指針,p3的值永不改變,即p3永遠指向變量i2,同時p3指向的是常量,即我們不能通過p3改變所指對象的值.
(e)
是合法的,p1指向一個常量,即我們不能通過p1改變所指對象的值
(f)
是非法的,引用本身不是對象,因此不能讓引用恆定不變
(g)
是合法的,i2是一個常量,r是一個常量引用
2.28
(a)
int *const cp
const 指針必須初始化
(b)
int *p1,*const p2
const指針必須初始化
©
const 常量必須要初始化 ic
(d)
const int *const p3;
p3是一個常量指針,指向的對象是一個int類型的常量
常量指針必須要初始化,所以錯誤
不合法
(e)
合法,但是p沒有指向任何實際的對象
2.29
(a)
合法的
(b)
非法的
普通指針p1指向了一個常量
而且,普通指針p1的值可以任意的改變,這與實際不符
©
非法
普通指針p1指向了一個常量
普通指針p1的值可以任意的改變,這與實際不符
(d)
非法
p3只能再定義的時候,被初始化,後來就不可以改變p3的指向了
(e)
非法的
p2是一個常量指針,只能再定義的時候,被初始化,後來就不可以改變p2的指向了
(f)
非法的
ic只能再定義的時候,被初始化
2.30
v2和p3是頂層const,分別表示一個整形常量和一個整形常量指針
p2和r2是底層const,分別表示它們所指(所引用的對象是常量)
2.31
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指向的對象的值,不會引起衝突
2.32
錯誤
指針不可以直接綁定一個int類型
根據題意,可以修改爲
int null = 0, * p = nullptr;
2.33
前三條語句都是正確的,因爲a,b,c都是整數
後三條都不太正確.
d,e都是指針,這樣肯定是錯誤的.
g是一個整型常量引用,他是不可以改變引用的對象的.
2.34
#include<iostream>
#include<string>
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;
}
2.35
這個是我自己寫的驗證程序
自己寫的
#include<iostream>
#include<string>
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<iostream>
#include<typeinfo>
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
2.36
#include<iostream>
#include<string>
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;
}
2.37
這題我套用了上一題的代碼
#include<iostream>
#include<string>
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;
}
2.38
這題答案,是我參考的
① auto類型說明符用編譯器計算變量的初始值來推斷其類型,而decltype雖然也讓編譯器分析表達式並得到它的類型,但是不計算表達式的值
② 編譯器推斷出來的auto類型有時候和初始值的類型並不完全一樣,編譯器會適當的改變結果類型使其更符合初始化的規則
例如:auto一般會忽略頂層const,而把底層的const保留下來,與之相反,decltype會保留變量的頂層const
③ 與auto不同,decltype的結果類型與表達式形式密切相關,如果變量名加了一對括號,則得到的類型與不加括號時會有不同.如果deltype使用的是一個不加括號的變量,則得到的結果就是改變量的類型;如果給變量加上了一層或多層括號,則編譯器將推斷得到引用類型
下面是一個例子
#include<iostream>
#include<typeinfo>
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;
}
2.39
2.40
struct Sales_data {
std::string bookNo; //書籍編號
unsigned units_sold = 0; //銷售量
double sellingprice = 0.0; //零售價
double saleprice = 0.0; //實售價
double discount = 0.0; //折扣
};
2.41
2.42
如果這篇文章對你有張幫助的話,可以用你高貴的小手給我點一個免費的贊嗎
相信我,你也能變成光.
如果你有任何建議,或者是發現了我的錯誤,歡迎評論留言指出.