2.1基本內置類型
C++定義了一套包括算術類型和空類型在內的基本數據類型。
2.1.1 算術類型
算術類型分為兩類:整型和浮點型。
算術類型的尺寸在不同機器上有所差別。下表中列出了C++標準規定的尺寸的最小值,同時允許編譯器賦予這些類型更大的尺寸。
除了布爾類型,其他整型可以劃分為帶符號的和無符號的兩種。帶符號類型可以表示正數、負數或0,無符號類型僅能表示大于等于0的值。
類型int、short、long和long long都是帶符號的,通過在這些類型名前添加unsigned就可以得到無符號類型。
字符型被分為三種:char、signed char和unsigned char。特別需要注意的是:類型char和類型signed char并不一樣。盡管字符型有三種,但是字符的表現形式只有兩種:帶符號的和無符號的。類型char實際上回表現為上述兩種形式的一種,具體是哪種由編譯器決定。
2.1.2 類型轉換
int main()
{
bool b = 42;//b=true
std::cout << "b=" << b<<std::endl;
int i = b; //i=1
i = 3.14; // i=3
double pi = i; //pi = 3.0
unsigned char c = -1; //假設char占8 byte,c的值為255
signed char c2 = 256;//假設char占 8 byte,c的值是未定義的
return 0;
}
當我們把非布爾值類型的算術值賦給布爾類型,初始值為0則結果為false,否則結果為true。
當我們把一個布爾值賦給非布爾類型時,初始值為false則結果為0,初始值為true則結果為1。
當把一個浮點數賦給整數類型時,結果值僅保留浮點數中小數點之前的部分。
當我們把一個整數值賦予給浮點類型時,小數部分記為0。如果該整數所占的空間超過了浮點類型的容量,精度可能有損失。
當我們賦給無符號類型一個超出它表示范圍的值時,結果是初始值對無符號類型表示數值總數取模后的余數。例如,8比特大小的unsigned char可以表示0至255區間內的值,表示的數值總數為256,如果我們賦了一個區間以外的值-1,則結果為
-1%256=255
。當我們賦給帶符號類型一個超出它表示范圍的值時,結果為未定義的。此時,程序可能繼續工作、可能崩潰,也可能產生垃圾數據。
含有無符號類型的表達式
unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl;//-84
std::cout << i + u << std::endl;//4294967264
在第一個輸出表達式里,兩個負整數想家得到了期望的結果。在第二個輸出表達式里,相加前首先把整數-42轉換成無符號數然后與無符號數相加-42%2^32+10=4294967264
。
當從無符號數中減去一個值時,不管這個值是不是無符號,我們都必須確保結果不能是一個負數。
unsigned u1 = 42, u2 = 10;
std::cout << u2 - u1 << std::endl; //4294967264 32%2^32
2.1.4 字面值常亮
整型
可以將整型字面量寫作十進制、八進制或十六進制。以0開頭的代表八進制數,以0x或0X開頭的代表十六進制。
通過添加下表中所列的前綴和后綴,可以改變整型、浮點型和字符型字面值的默認類型。
2.3 復合類型
復合類型是指基于其他類型定義的類型。我們將介紹兩種:引用和指針。
2.3.1 引用
引用為對象起了另外一個名字,引用類型引用另外一種類型。通過將聲明符寫成&d的形式來定義引用類型,其中d是聲明的變量名。
一般在初始化變量時,初始值會被拷貝到新建的對象中。然而定義引用時,程序把引用和它的初始值綁定在一起,而不是將初始值拷貝給引用。一旦初始化完成,引用將和它的初始值對象一直綁定在一起。因為無法令引用重新綁定到另外一個對象,因此引用必須初始化。
int main()
{
int ival = 1024;
int &refVal = ival;
refVal = 2; //把2賦值給refVal指向的對象,此處即是賦值給ival
std::cout << "ival=" << ival << std::endl;//ival=2
int ii = refVal;
return 0;
}
引用只能綁定在對象上,而不能與字面值或某個表達式的計算結果綁定在一起。
int &refVal = 10;//錯誤:引用類型的初始值必須是一個對象
double dval = 3.14;
int &refVal2 = dval;//錯誤:此處引用類型的初始值必須是int型對象
2.3.2 指針
指針是指向另外一種類型的復合類型。與引用類似,指針也實現了對其他對象的間接訪問。然而指針與引用相比又有很多不同點。其一、指針本身就是一個對象,允許對指針復制和拷貝,而且在指針的生命周期內它可以先后指向幾個不同的對象。其二,指針無需再定義時賦初值。與其他內置類型一樣,在塊作用于內定義指針如果沒有被初始化,也將用用一個不確定的值。
獲取對象的地址
指針存放某個對象的地址,要想獲取該地址,需要使用取地址符(操作符&)
int ival = 42;
int *p = &ival;//p存放變量ival的地址,p是指向變量ival的指針。
利用指針訪問對象
如果指針指向了一個對象,則允許使用解引用符(操作符)*來訪問該對象。
int ival = 42;
int * p = &ival;
*p = 0;//由解引用符*得到指針p所指的對象,即可經由p為變量ival賦值
空指針
空指針(null pointer)不指向任何對象,在試圖使用一個指針之前代碼可以首先檢查他是否為空。
生成空指針的方法有三種:
- 使用字面值
nullptr
來初始化指針,也就是C++11新標準剛剛引入的一種方法。nullptr
是一種特殊類型的字面值,它可以被轉換成任意其他的指針類型。
int *p1 = nullptr;
- 通過將指針初始化為字面值0來生成空指針。
int *p2 = 0;
- 用一個名為NULL的預處理變量來給指針賦值,這個變量在頭文件cstdlib中定義,它的值就是0。
int *p3 = NULL;