C++ Primer 讀書筆記2.1
1、C++中認為:void修飾返回值表示:不返回任何值;void修飾引數表列,表示:不接受任何引數、若引數表列裡什麼也不寫,表示:可接受任意型別的引數。
2、C++中規定short <= int <= long <= long long
3、注意隱式型別轉換例項:
bool b = 42;// b = 1 ( 因為b為布林值,非0即1)
int i = b; // i = 1
i = 3.141; // i =3 (因為i為整型值)
double pi = i;// pi = 3.0
unsigned char c = -1;// c = 255 (char型佔8bit,(2^8+(-1))% 2^8 = 255)
singed char c2 = 256 // c2 = 未知錯誤(當給有符號數一個超出其範圍的值,將使程式發生不可預測的結果)
4、當有符號數和無符號數一起計算時,都將轉換成無符號數,再進行計算,但儘量避免此類情況的發生。
5、轉義序列
換行符\n橫向製表符\t報警(響鈴)符\a
縱向製表符\v退格符\b雙引號\"
反斜槓\\問號\?
單引號\'
回車符\r進紙符\f
泛化的轉義字元:\x後的一位或多位十六進位制數;\後的1~3位八進位制數。例如:
\7 (響鈴)\12 (換行)\40(空格)\0(空字元)\115 (字元M)\x4d (字元M)
6、指定字面值的型別
表2.1: 指定字面值型別 |
|||
字元和字串字面值 |
|||
字首 |
含義 |
型別 |
|
u |
Unicode16字元 |
Char16_t |
|
U |
Unicode32字元 |
Char32_t |
|
L |
寬字元 |
Wchar_t |
|
u8 |
UTF-8(僅用於字串字面常量) |
Char |
|
整型字面值 |
浮點型字面值 |
||
字尾 |
最小匹配型別 |
字尾 |
型別 |
U或u |
Unsigned |
F或f |
float |
L或l |
long |
L或l |
long double |
LL或ll |
long long |
指標字面值:nullptr布林字面值:true 或 false
7、初始化C++定義了初始化的多種不同方式,如以下4個語句均可實現定義units_sold並將其初始化為0:
int units_sold = 0 ;
int units_sold = {0};
int units_sold{0};
int units_sold(0);
注意,當使用{}的形式來初始化變數,如果存在丟失資訊的風險時,編譯器會報錯,其它形式有警告,但不報錯。
如:long double ld = 3.1415926536;
int a{ld} , b = {ld} ;//錯誤,轉換未執行,因為存在資訊丟失的風險
int c(ld) , d = (ld) ;//正確,轉換執行,且確實丟失了部分值
預設初始化:
string 預設初始化一個空字串;全域性變數預設初始化為0;
注意:未初始化的變數是一個不確定的值,使用未初始化的值可能使程式發生不可預測的結果。所以建議為了程式安全考慮,建議變數在定義時一定記得初始化。
8、識別符號
a 識別符號必須由字母、數字和下劃線組成,且以字母或下劃線開頭;
b c++中所保留的函式或關鍵字不能用作識別符號 ;
c 使用者自定義的標誌符不可以連續出現兩個下劃線,也不能以下劃線緊跟大寫字母開頭;
d 定義在函式體外的識別符號也不能以下劃線開頭。
變數命名規則:
a 識別符號要能體現實際含義
b 變數名一般用小寫字母
c 使用者自定義的類名一般用大寫字母開頭
d 標誌符如果由多個單片語成一般單詞之間需要有明顯的區分,一般以首字母大寫或下劃線區分
9、引用
a 引用即別名:引用不是物件,它只是物件的一個別名。
b 定義引用時必須對其初始化,且之後不可以更改繫結的物件,也不能定義引用的引用。
c 引用的型別和其繫結的物件之間的型別必須嚴格匹配,除以下兩種情況:
i 初始化常量引用時允許用任意表達式作為初始值,只要求該表示式的結果能轉換成引用型別即可。如: double dval = 3.14 ; const int &ri = dval;
ii 允許將一個常量引用繫結到非const物件、字面值、表示式上。如:const int &r1 = (32+5);
10、指標
a 空指標:
幾種生成空指標的方式:int *p1 = nullptr;int *p1 = 0; int *p1 = NULL(需要加#include cstdlib);
空指標可用於存放任何型別物件的地址,同時也不能直接操作空指標所指的物件。
b 指向指標的引用:因為引用不是一個物件故不可以定義指向引用的指標,但可以定義指向指標的引用。如 int i = 42; int *p = & i ; int *&r = p 此處的r即為指向指標的引用
指標和引用的區別:
指標是“指向”記憶體中的某個物件,而引用是“繫結到”記憶體中的某個物件,他們之間都實現了物件的間接訪問,二者的區別主要有:
其一:指標本身就是一個物件,允許對指標進行賦值和拷貝,而且在指標的生命週期中它可以指向不同的物件;而引用不是一個物件,僅僅是物件的一個別名,可以對其賦值,但不可以拷貝,且一旦繫結到某個物件上將無法更改。
其二:指標可以隨時進行初始化,即不必定義時;引用則必須在定義時就進行初始化。
11、const限定符
a const修飾的物件一經建立,其值將不能再改變,所以const修飾的變數定義時必須初始化,且之後不可以做左值。
b const int 可以和普通int 值一樣的參與算術運算,只要不改變其值,其和普通int值基本沒區別。
c const物件的作用域為檔案作用域。若要使其在各個檔案中共享必須在定義和引用前同時加extern 關鍵字
d “常量的引用”即“對const的引用”。
i 初始化常量引用時允許用任意表達式作為初始值,只要求該表示式的結果能轉換成引用型別即可。
ii 允許將一個常量引用繫結到非const物件、字面值、表示式上。
12、頂層const
a、我們知道,指標本身是一個物件,同時它還可以指向另一個物件,故就存在指標本身是不是常量和它指向的物件是不是常量,這兩個相互獨立的問題。
頂層const(top-level const)表示:指標本身是個常量,或者任意的物件是常量;
底層const(low-level const)表示:指標所指物件是個常量,底層const只與指標、引用等複合型別的基本型別部分有關。注意:用於宣告引用的const都是底層const。
b、當執行物件的拷貝操作時,常量是頂層const還是底層const區別明顯。其中,頂層const不受影響,即執行拷貝操作,被拷貝物件的值不會被改變。但,底層const在執行拷貝操作時,烤入和拷出的物件必須具有相同的底層const資格,或者兩個物件的資料型別必須能夠轉換。一般來說非常量可以轉換為常量,反之不行。
13、常量表達式
常量表達式:其值不會改變並且在編譯階段就可以得到計算結果的表示式。字面值和用常量表達式初始化的const物件都是常量表達式。
一個物件是不是常量表達式由它的資料型別和初始值共同決定的。
C++11新標準規定,允許將變數宣告為constexpr型別以便編譯器來驗證變數的值是否是一個常量表達式。宣告為constexpr的變數一定是一個常量,且必須用常量表達式進行初始化。
字面值型別:算數型別、引用、指標。指標在定義為constexpr時,初始值必須是nullptr或者0,或者儲存於某個固定地址的物件(函式體內定義的變數一般來說並非存放在固定地址當中,因此constexpr指標不能指向這樣的變數);同時允許函式定義一類有效範圍超出函式體本身的變數,這類變數和函式體外定義的變數一樣有固定地址;constexpr修飾的指標,constexpr修飾符只對指標有效,不影響指標所指物件;constexpr修飾的指標可以指向常量也可以指向非常量。
不屬於字面值型別:自定義類、IO庫、string型別。也就不能定義為constexpr。
補充:部分課後習題答案
練習 2.3
unsigned u = 10;u2 = 42;
std :: cout << u2 - u << std :: endl; // 32
std :: cout << u - u2 << std :: endl; // (2^32-32)%2^32=4294967264 (其中int 型佔32bit ,2^32=4294967296)
int i = 10,i2 = 42;//預設為有符號
std :: cout << i2 - i << std :: endl; // 32
std :: cout << i - i2 << std :: endl; // -32
std :: cout << i - u << std :: endl; // 0
std :: cout << u - i << std :: endl; // 0
練習2.5:指出下述字面值的資料型別並說明每組內幾種字面值的區別
(a)'a'//字元a ;L'a'//寬字元a ;"a"//字串a ;L'a'//寬字元型字串a ;,
(b)10//int 10 ;10u//無符號數10 ;10L//long int 10 ;10uL//long unsigned int 10 ;
012//八進位制數表示的10;0xc/ /十六進位制表示的10
練習2.6:下面兩組定義是否有區別,有請敘述之
int month = 9 , day = 7 ;//十進位制表示的int month = 9 , day = 7 ;編譯可通過。
int month = 09 , day = 07 ;//八進位制表示的int month = 9(錯誤了,正確表示法為:month =0 11), day = 7 ;編譯無法通過,改後可以。
練習2.9:解釋下列定義的含義。對於非法的,說明其錯誤原因並改正
(a) std :: cin >> int input_value ; //非法,輸入運算子後面必須跟一個明確的已經定義好的變數名而不是定義變數語句。改正:int input_value ;std :: cin >> input_value ;
(b) int i = {3.14} ;//非法,因為用{}進行初始化時發生資訊丟失會報錯,程式無法編譯執行。改正:int i = (3.14) 或 float i = {3.14};
(c) double salary = wage =9999.99;//非法,宣告多個變數需要用,將其隔開。改正:double salary , wage ;salary = wage =9999.99;
(d)int i = 3.14 ; //合法,但會警告。建議改為:float i = 3.14;
練習2.27:下面那些初始化是合法的?說明原因
(a)int i = -1,&r = 0 ;//不合法,因為其是普通的引用而非常量引用,所以不能用字面值
(b)int * const p2 = &i//合法的,常指標可以指向普通的指標
(c)const int i = -1 , &r = 0 //合法,常量引用可以直接使用字面值
(d)const int * const p3 = &i //合法,只是p3將永遠指向&i,不可以改變其指向,同時也不可以通過p3來更改i的值
(e)const int *p1 = &i ;//合法,只是不能通過p1來更改i的值
(f)const int &const r2 ;//非法,引用本身不是物件,所以不可以對引用再加const即最左邊的const錯誤,同時,引用必須初始化。
(g)const int i2 = i ; &r = i //合法,常量引用可以繫結到非常量引用上。
練習2.28:說明下面的定義的意義,挑出其中不合法的
(a)int i ,*const cp ;//不合法,i是普通的int型OK,但cp為常指標,其指向不可以改變,所以必須初始化
(b)int *p1, * const p2; //不合法,p1為普通指標,OK;但p2同cp一樣為常指標,其指向不可以改變,所以必須初始化
(c)const int ic , &r = ic;//不合法,ic 為const int型變數,所以必須初始化;若ic已初始化,r為其常量引用,OK。
(d)const int * const p3 ;//不合法,同cp一樣,p3為常指標,其指向不可以改變,所以必須初始化
(e)const int *p ;//合法,但是p沒有初始化,如若直接使用會造成不可預知的結果,所以不建議如此使用。
練習2.29:假設已經有了上一個練習中定義的那些變數,則下面的哪些語句是合法的?並說明原因
(a)i = ic ; //合法,只要不改變const int 型的變數的值,其使用方法和普通int型沒區別,所以合法
(b)p1 = p3 ; //不合法,const型別的指標可以接受非const的指標但反過來非const型別的指標不可以接受指向const變數的指標
(c)p1 = ⁣//不合法,普通指標不可以指向常變數;反過來常指標可以指向普通變數
(d)p3 = ⁣//不合法,p3是一個常指標,不可以改變其指向
(e)p2 = p1;//不合法,p2是常指標,不可以被賦值
(f)ic = *p3 ;//不合法,ic是常變數,不可以被賦值
p57頁例子
int i = 0;
int *const p1 = &i ;//頂層const,指標p1自身不可改變
const int ci = 42 ;//頂層const,ci本身不可改變
const int *p2 = &ci ; //底層const,指標p2所指內容不可改變
const int *const p3 ;//前一個const是底層const,表示p3所指內容不可改變;後一個const是頂層const表示p3本身不可改變
const int &r = ci ;//底層const,所有修飾引用的const均為底層const
p58頁例子(部分變數定義見上題)
int *p = p3;//錯誤,p3包含底層const定義,而p沒有
p2 = p3;//正確,p2和p3都具有底層const
p2 = &i;//正確,非const可以轉換成const
int &r = ci;//錯誤,非const型別的引用無法繫結到const型別的變數上
const int &r2 = i//正確,const型別的引用可以繫結到非const型別上