C++ Primer Plus 学习笔记(第 4 章 复合类型)
C++ Primer Plus 學(xué)習(xí)筆記
第 4 章 復(fù)合類型
數(shù)組
數(shù)組(array)是一種數(shù)據(jù)格式,能夠存儲(chǔ)多個(gè)同類型的值。
要?jiǎng)?chuàng)建數(shù)組,可使用聲明語(yǔ)句。數(shù)組聲明應(yīng)指出以下三點(diǎn):
- 存儲(chǔ)在每個(gè)元素的值的類型;
- 數(shù)組名;
- 數(shù)組中的元素?cái)?shù)。
聲明數(shù)組的通用格式如下:
typename arrayName[arraySize];表達(dá)式arraySize指定元素?cái)?shù)目,必須是整數(shù)或const值,也可以是常量表達(dá)式,即其中所有的值在編譯時(shí)都是已知的,即不能是變量。
使用下標(biāo)或索引訪問元素,C++數(shù)組從0開始編號(hào)。編譯器不會(huì)檢查使用的下標(biāo)是否有效。
數(shù)組的初始規(guī)則
只有在定義數(shù)組時(shí)才能使用初始化,此后就不能使用了,也不能將一個(gè)數(shù)組賦給另一個(gè)數(shù)組。
然而,可以使用下標(biāo)分別給數(shù)組中的元素賦值。
初始化數(shù)組時(shí),提供的值可以少于數(shù)組的元素?cái)?shù)目。
如果只對(duì)數(shù)組的一部分進(jìn)行初始化,則編譯器將把其他元素設(shè)置為0。
如果初始化數(shù)組時(shí)方括號(hào)內(nèi)為空,C++編譯器將計(jì)算元素個(gè)數(shù)。此方法對(duì)將字條數(shù)組初始化為一個(gè)字符串來說比較安全。
C++11 數(shù)組初始化方法
C++11將使用大括號(hào)的初始化(列表初始化)作為一種通用的初始化格式,可用于所有類型。
數(shù)組以前就可以使用列表初始化,但C++11中的列表初始化新增了一些功能。
首先,初始化數(shù)組時(shí),可以省略等號(hào)(=)。
其次,可不在大括號(hào)內(nèi)包含任何東西,這將把所有元素都設(shè)置為零。
第三,列表初始化禁止縮窄轉(zhuǎn)換。
字符串
字符串是存儲(chǔ)在內(nèi)存的連續(xù)字節(jié)中的一系列字符。C++處理字符串的方式有兩種。第一種來自C語(yǔ)言,常被稱作C-風(fēng)格字符串(C-style string)。另一種是基于string類庫(kù)的方法。
C-風(fēng)格字符串具有一種特殊的性質(zhì):空字符(null character)結(jié)尾,空字符實(shí)寫作\0,其ASCII碼為0,用來標(biāo)記字符串的結(jié)尾。
將字符數(shù)組初始化為字符串的方法——只需使用一個(gè)引號(hào)括起的字符串即可,這種字符串被稱為字符串常量(string constant)或字符串字面值(string literal)。
用引號(hào)括起的字符串常量隱式地包括結(jié)尾的空字符,因此不用顯示地包括它。
注意:字符串常量(使用雙引號(hào))不能與字符常量(使用單引號(hào))互換。
拼接字符串常量
C++允許拼接字符串字面值,任何兩個(gè)由空白(空格、制表符和換行符)分隔的字符串常量都將自動(dòng)拼接成一個(gè)。
注意:拼接時(shí)不會(huì)在被連接的字符串之間添加空格,第一個(gè)字符串中的\0字符將被第二個(gè)字符串的第一個(gè)字符取代。
在數(shù)組中使用字符串
要將字符串存儲(chǔ)到數(shù)組中,最常用的方法有兩種——將數(shù)組初始化為字符串、將鍵盤或文件輸入讀入到數(shù)組中。
字符串輸入
cin使用空白(空格、制表符和換行符)來確定字符串的結(jié)束位置。
每次讀取一行字符串輸入
iostream中的類(如cin)提供了一些面向行的類成員函數(shù):getline()和get()。這兩個(gè)函數(shù)都讀取一行輸入,直到到達(dá)換行符。然而,隨后getline()將丟棄換行符,而get()將換行符保留在序列中。
面向行的輸入getline()
cin.getline(charArray, strSize);getline()函數(shù)每次讀取一行,最多讀取strSize-1個(gè)字符,通過換行符確定行尾,但不保存換行符,存儲(chǔ)時(shí)用空字符代替換行符。
面向行的輸入get()
get()第一種工作方式與getline()類似,接受相同的參數(shù),但不再丟棄換行符,而是將它保留在輸入序列中。不帶參數(shù)即可讀取一個(gè)字符,包括換行符。
cin.get(charArray, strSize); cin.get();另一種使用get()的方式是將兩個(gè)類成員函數(shù)拼接起來(合并),getline()也可以,其效果與兩次調(diào)用相同。
cin.get(charArray, strSize).get(); cin.getline(charArray1, strSize).getline(charArray2, strSize);空行和其他問題
當(dāng)get()讀取空行后新塘鎮(zhèn)設(shè)置失效位,接下來的輸入被阻斷,可使用cin.clear();恢復(fù)輸入。
如果輸入行包含的字符數(shù)比指定的多,則getline()和get()將把余下的字符保留在輸入隊(duì)列中,而get()還會(huì)設(shè)置失效位,并關(guān)閉后面的輸入。
混合輸入字符串和數(shù)字
在cin讀取數(shù)字后,在getline()之前要丟棄換行符,可使用沒有參數(shù)的get()。
string 類簡(jiǎn)介
C++98標(biāo)準(zhǔn)通過添加string類擴(kuò)展了C++庫(kù),可以使用string類型的對(duì)象來存儲(chǔ)字符串。string類使用起來比數(shù)組簡(jiǎn)單,同時(shí)提供了將字符串作為一種數(shù)據(jù)類型的表示方法。
要使用string類,必須在程序中包含頭文件string。string類位于名稱空間std中,因此必須提供一條using編譯指令,或使用std::string來引用它。string類定義隱藏了字符串的數(shù)組性質(zhì),可像普通變量那樣處理字符串。
在很多方面,使用string對(duì)象的方式與使用字符數(shù)組相同。
- 可以使用C-風(fēng)格字符串來初始化string對(duì)象。
- 可以使用cin來將鍵盤輸入存儲(chǔ)到string對(duì)象中。
- 可以使用cout來顯示string對(duì)象。
- 可以使用數(shù)組表示法來訪問存儲(chǔ)在string對(duì)象中的元素。
string對(duì)象與字符數(shù)組之間的主要區(qū)別是,可以將string對(duì)象聲明為簡(jiǎn)單變量,而不是數(shù)組。
類設(shè)計(jì)讓程序能夠自動(dòng)處理string的大小。這使用與使用數(shù)組相比,使用string對(duì)象更方便,也更安全。
未被初始化的string對(duì)象的長(zhǎng)度被自動(dòng)設(shè)置為0。
C++11 字符串初始化
C++11也允許將列表初始化用于C-風(fēng)格字符串和string對(duì)象。
賦值、拼接和附加
不能將一個(gè)數(shù)組賦給另一個(gè)數(shù)組,但可以將一個(gè)string對(duì)象賦給另一個(gè)string對(duì)象。
可以使用運(yùn)算符+將兩個(gè)string對(duì)象合并起來,還可以使用運(yùn)算符+=將字符串附加到string對(duì)象的末尾。
可以將C-風(fēng)格字符串或string對(duì)象與string對(duì)象相加,或?qū)⑺鼈兏郊拥絪tring對(duì)象的末尾。
strlen()是一個(gè)常規(guī)函數(shù),size()是一個(gè)類方法。
string 類 I/O
可以使用cin和運(yùn)算符>>來將輸入存儲(chǔ)到string對(duì)象中,也可以使用cout和運(yùn)算符<<來顯示string對(duì)象,其句法與C-風(fēng)格字符串相同。但每次讀取一行而不是一個(gè)單詞時(shí),使用的句法不同。
cin.getline(charry, 20); \\類方法 getline(cin, str); \\不是類方法在引入string類之前,C++就有了iostream類,所以iostream沒有處理string對(duì)象的類方法。
其他形式的字符串字面值
創(chuàng)建wchar_t、char16_t和char32_t的字符串常量時(shí),C++分別使用前綴L、u和U表示。
C++11還支持Unicode字符編碼方案UTF-8,使用前綴u8來表示。
C++新增的另一種類型是原始(raw)字符串,在原始字符串中,字符表示的就是自己。
原始字符串將"(和)"用作界定符,并使用前綴R來標(biāo)識(shí)原始字符串。可以在默認(rèn)界定符之間添加任意數(shù)量的基本字符,但空格、左括號(hào)、右括號(hào)、斜杠和控制字符(如制表符和換行符)除外。
可將前綴R與其他字符串前綴結(jié)合使用,以標(biāo)識(shí)wchar_t等類型的原始字符串。可將R放在前面,也可以放在后面,如Ru、UR等。
結(jié)構(gòu)簡(jiǎn)介
結(jié)構(gòu)是用戶定義的類型,創(chuàng)建結(jié)構(gòu)包括兩步。首先,結(jié)構(gòu)聲明——定義這種類型的數(shù)據(jù)屬性;然后,按描述創(chuàng)建結(jié)構(gòu)變量(結(jié)構(gòu)數(shù)據(jù)對(duì)象)。
struct type_name {member_type1 member_name1;member_type2 member_name2;member_type3 member_name3;...... }; type_name object_names; object_names.nember_name1;C++允許在聲明結(jié)構(gòu)變量時(shí)省略關(guān)鍵字struct,可以使用成員運(yùn)算符.來訪問成員。訪問類成員函數(shù)的方式是從訪問結(jié)構(gòu)成員變量的方式衍生而來的。
在程序中使用結(jié)構(gòu)
結(jié)構(gòu)聲明的位置很重要。外部聲明可以被其后面的任何函數(shù)使用,而內(nèi)部聲明只能被該聲明所屬的函數(shù)使用。通常應(yīng)使用外部聲明,這樣所有的函數(shù)都可以使用這種類型的結(jié)構(gòu)。
變量也可以在函數(shù)內(nèi)部和外部同義,外部變量由所有的函數(shù)共享。C++不提倡使用外部變量,但提倡使用外部結(jié)構(gòu)聲明。另外,在外部聲明符號(hào)常量通常更合理。
C++11 結(jié)構(gòu)初始化
首先,C++11也支持將列表初始化用于結(jié)構(gòu),且等號(hào)=是可選的。
其次,如果大括號(hào)內(nèi)未包括任何東西,各個(gè)成員都將被設(shè)置為零。
最后,不允許縮窄轉(zhuǎn)換。
結(jié)構(gòu)可以將 string 類作為成員
一定要讓結(jié)構(gòu)定義能夠訪問名稱空間std,為此,可以將using編譯指令移到結(jié)構(gòu)定義之前,也可以使用類型聲明std::string。
其他結(jié)構(gòu)屬性
C++使用戶定義的類型與內(nèi)置類型盡可能相似。例如,可以將結(jié)構(gòu)作為參數(shù)傳遞給函數(shù),也可以讓函數(shù)返回一個(gè)結(jié)構(gòu)。另外,還可以使用賦值運(yùn)算符=將結(jié)構(gòu)賦給另一個(gè)同類型的結(jié)構(gòu),即使成員是數(shù)組,這種賦值被稱為成員賦值。
可以同時(shí)完成定義結(jié)構(gòu)和創(chuàng)建結(jié)構(gòu)變量的工作,只需將變量名放在結(jié)束括號(hào)后面即可,甚至可以初始化以這種方式創(chuàng)建的變量。
然而,將結(jié)構(gòu)定義與變量聲明分開,可以使用程序更易于閱讀和理解。
還可以聲明沒有名稱的結(jié)構(gòu)類型,方法是省略名稱,同時(shí)定義一種結(jié)構(gòu)類型和這一個(gè)這種類型的變量。但這種類型沒有名稱,因此以后無(wú)法再創(chuàng)建這種類型的變量。
結(jié)構(gòu)數(shù)組
可以創(chuàng)建元素是結(jié)構(gòu)的數(shù)組,方法和創(chuàng)建基本類型數(shù)組完全相同。其中每個(gè)元素可以與成員運(yùn)算符一起使用。
要初始化結(jié)構(gòu)數(shù)組,可以結(jié)合使用初始化數(shù)組的規(guī)則(用逗號(hào)分隔每個(gè)元素,并將這些值用花括號(hào)括起來)和初始化結(jié)構(gòu)的規(guī)則(用逗號(hào)分隔每個(gè)成員的值,并將這些值用花括號(hào)括起來)。
結(jié)構(gòu)中的位字段
與C語(yǔ)言一樣,C++也允許指定占用特定位數(shù)的結(jié)構(gòu)成員,這使得創(chuàng)建與某個(gè)硬件設(shè)備上的寄存器對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)非常方便。字段的類型就為整數(shù)或枚舉,接下來是冒號(hào),冒號(hào)后面是一個(gè)數(shù)字,指定使用的位數(shù)。也可以使用沒有名稱的字段來提供間距。每個(gè)成員都被稱為位字段(bit field)。
struct torgle_register {unsigned int SN : 4;unsigned int : 4;bool goodIn : 1;bool goodTorgle : 1; }; torgle_register tr = { 14, true, false }; if (tr.goodIn)位字段通常用在低級(jí)編程中。一般來說,可以使用整型和按位運(yùn)算符來代替這種方式。
共用體
共用體(union)是一種數(shù)據(jù)結(jié)構(gòu),它能夠存儲(chǔ)不同的數(shù)據(jù)類型,但只能同時(shí)存儲(chǔ)其中的一種類型。
union one4all {int int_val;long long_val;double double_val; };可以使用one4all變量來存儲(chǔ)int、long或double,條件是在不同的時(shí)間進(jìn)行。
由于共用體每次只能存儲(chǔ)一個(gè)值,因此它必須有足夠的空間來存儲(chǔ)最大的成員,所以,共用體的長(zhǎng)度為最大成員長(zhǎng)度。
共用體的用途之一是,當(dāng)數(shù)據(jù)項(xiàng)使用兩種或更多種格式(但不會(huì)同時(shí)使用)時(shí),可節(jié)省空間。例如,假設(shè)管理一個(gè)小商品目錄,其中有一些商品ID為整數(shù),而另一些的ID為字符串。在這種情況下,可以這樣做。
struct widget {char brand[20];int type;union id{long id_num;char id_char[20];}id_val; }; ... widget prize; ... if(prize.type == 1)cin >> prize.id_val.id_num; elsecin >> prize.id_val.id_char;匿名共用體沒有名稱,其成員將成為位于相同地址的變量。顯然,每次只有一個(gè)成員是當(dāng)前的成員:
struct widget {char brand[20];int type;union{long id_num;char id_char[20];}; }; ...widget prize; ...if(prize.type == 1)cin>>prize.id_num; elsecin>>prize.id_char;由于共用體是匿名的,因此id_num和id_char被視為prize的兩個(gè)成員,它們的地址相同,所以不需要中間標(biāo)識(shí)符id_val。程序員負(fù)責(zé)確定當(dāng)前哪個(gè)成員是活動(dòng)的。
共用體常用于(但并非只用于)節(jié)省內(nèi)存。C++還常用于嵌入式系統(tǒng)編程,如控制烤箱、MP3播放器或火星漫步者的處理器。對(duì)這些應(yīng)用程序來說,內(nèi)存可能非常寶貴。另外,共用體還常用于操作系統(tǒng)數(shù)據(jù)結(jié)構(gòu)或硬件數(shù)據(jù)結(jié)構(gòu)。
枚舉
C++的enum工具提供了另一種創(chuàng)建符號(hào)常量的方式,可以代替const。它還允許定義新類型,但必須按嚴(yán)格的限制進(jìn)行。使用enum的句法與使用結(jié)構(gòu)相似。
enum color_set1 {RED, ORANGE, YELLOW, GREEN, BLUE, WHITE, BLACK};將RED、ORANGE、 YELLOW等作為符號(hào)常量,叫做枚舉量。
在默認(rèn)情況下,將整數(shù)賦給枚舉量,從0開始。也可通過顯式地指定整數(shù)值來覆蓋默認(rèn)值。
可能用枚舉名來聲明這種類型的變量。
在不進(jìn)行強(qiáng)制類型轉(zhuǎn)換的情況下,只能將定義枚舉時(shí)使用的枚舉量賦給這種枚舉變量。
對(duì)于枚舉,只定義了賦值運(yùn)算符,沒有為枚舉定義算術(shù)運(yùn)算。可以在算術(shù)表達(dá)式中同時(shí)使用枚舉和常規(guī)整數(shù),枚舉將轉(zhuǎn)換為整數(shù)。
如果整數(shù)值是有效的,則可通過強(qiáng)制類型轉(zhuǎn)換,將它賦給枚舉變量。
實(shí)際上,枚舉更常被用來定義相關(guān)的符號(hào)常量,而不是新類型。如果打算只使用常量,而不創(chuàng)建枚舉變量,則可以省略枚舉類型的名稱。
設(shè)置枚舉量的值
可以使用賦值運(yùn)算符來顯式地設(shè)置枚舉量的值,指定的值必須是整數(shù)。也可以只顯式地定義其中一些枚舉量的值,沒有被顯式定義的枚舉量的值將比其前面的枚舉量大1。
可以創(chuàng)建多個(gè)值相同的枚舉量。
枚舉的聚會(huì)范圍
最初,對(duì)于枚舉來說,只有聲明中指出的那些值是有效的。然而,C++現(xiàn)在通過強(qiáng)制類型轉(zhuǎn)換,增加了可賦值給枚舉變量的合法值。每個(gè)枚舉都有取值范圍(range),通過強(qiáng)制類型轉(zhuǎn)換,可以將取值范圍中的任何整數(shù)值賦給枚舉變量,即使這個(gè)值不是枚舉值。
取值范圍的定義如下。
首先,要找出上限,需要知道枚舉量的最大值。大于這個(gè)最大值的、最小的2次冪減1,就是取值范圍的上限。
要計(jì)算下限,需要知道枚舉量的最小值。如果不小于0,則取值范圍的下限就是0;否則,采用與尋找上限相同的方法,但加上負(fù)號(hào)。
選擇多少空間來存儲(chǔ)枚舉由編譯器決定。
指針和自由存儲(chǔ)空間
指針是一個(gè)變量,其存儲(chǔ)的是值的地址,而不是值本身。
對(duì)變量應(yīng)用地址運(yùn)算符&,可以獲得它的地址。
使用常規(guī)變量時(shí),值是指定的量,而地址為派生量。
使用指針變量時(shí),將地址視為指定的量,而將值視為派生量。
指針名表示地址,*運(yùn)算符被稱為間接值或解除引用運(yùn)算符,將其用于指針,可以得到該地址外存儲(chǔ)的值。
聲明和初始化指針
指針聲明必須指定指針指向的數(shù)據(jù)的類型。
int * p1, * p2; int higgens = 5; int * pt = &higgens;*運(yùn)算符兩邊的空格是可選的。對(duì)每個(gè)變量,都需要使用一個(gè)*。
可以在聲明語(yǔ)句中初始化指針。
指針的危險(xiǎn)
在C++創(chuàng)建指針時(shí),計(jì)算機(jī)將分配用來存儲(chǔ)地址的內(nèi)存,但不會(huì)分配用來存儲(chǔ)指針?biāo)赶虻臄?shù)據(jù)的內(nèi)存。
警告:一定要在對(duì)指針應(yīng)用解除引用運(yùn)算符*之前,將指針初始化為一個(gè)確定的、適當(dāng)?shù)牡刂贰?/p>
指針與數(shù)字
指針不是整型,不能簡(jiǎn)單地將整型同給指針,應(yīng)通過強(qiáng)制類型將數(shù)字轉(zhuǎn)換為適當(dāng)?shù)牡刂奉愋汀?/p> int * pt = (int *)0xB0000000;
使用 new 來分配地址
將指針初始為變量的地址,變量是在編譯時(shí)分配的有名字的地址,指針只是可以通過名稱直接訪問的地址提供了一個(gè)別名。
指針真正的用武之地在于,在運(yùn)行階段分配未命名的內(nèi)存以存儲(chǔ)值。在這種情況下,只能通過指針來訪問內(nèi)存。
C++用new運(yùn)算符來分配內(nèi)存。
new運(yùn)算符根據(jù)類型來確定需要多少字節(jié)的內(nèi)存,然后,找到這樣的內(nèi)存,并返回其地址。
我們說pt指向一個(gè)數(shù)據(jù)對(duì)象,它指的是為數(shù)據(jù)項(xiàng)分配的地址,因此,變量也是數(shù)據(jù)對(duì)象,但指向的內(nèi)存不是變量。
在C++中,值為0的指針被稱為空指針(null pointer)。C++確保空指針不會(huì)指向有效的數(shù)據(jù)。C++提供了檢測(cè)并處理內(nèi)存失敗的工具。
使用 delete 釋放內(nèi)存
使用deltet運(yùn)算符,能在使用完內(nèi)存后,將其歸還給內(nèi)存池,歸還或釋放(free)的內(nèi)存可供程序的其他部分使用。
使用deltet時(shí),后面要加上指向內(nèi)存塊的指針(這些內(nèi)存塊最初是用new分配的。
deltet釋放內(nèi)存,但不會(huì)刪除指針。
一定要配對(duì)使用new和deltet,否則將發(fā)生內(nèi)存泄露(memory leak),即被分配的內(nèi)存再也無(wú)法使用。
不要嘗試釋放已經(jīng)釋放的內(nèi)存塊,C++標(biāo)準(zhǔn)指出,這樣做的結(jié)果將是不確定的。也不能用deltet來釋放聲明變量所獲得的內(nèi)存。
只能用deltet來釋放使用new分配的內(nèi)存,但對(duì)空指針使用deltet是安全的。
注意:使用deltet的關(guān)鍵在于,將它用于new分配的內(nèi)存。這并不意味著要使用用于new的指針,而是用于new的地址。
使用 new 來創(chuàng)建動(dòng)態(tài)數(shù)組
通過聲明創(chuàng)建數(shù)組,在編譯時(shí)給數(shù)組分配內(nèi)存,稱為靜態(tài)聯(lián)編。使用new時(shí),在需要的時(shí)候創(chuàng)建數(shù)組,還可選擇數(shù)組的長(zhǎng)度,這稱為動(dòng)態(tài)聯(lián)編。這種數(shù)組叫做動(dòng)態(tài)數(shù)組。
使用 new 創(chuàng)建動(dòng)態(tài)數(shù)組
創(chuàng)建動(dòng)態(tài)數(shù)組,要將數(shù)組的元素類型和元素?cái)?shù)目告訴new。必須在類型名后加上方括號(hào),其中包含元素?cái)?shù)目。
type_name * point_name = new type_name [num_elements]; delete [] point_name;new運(yùn)算符返回第一個(gè)元素的地址。delete后的方括號(hào)表示釋放整個(gè)數(shù)組。不能使用sizeof運(yùn)算符來確定動(dòng)態(tài)分配的數(shù)組包含的字節(jié)數(shù)。
使用new和delete時(shí),應(yīng)遵循的規(guī)則:
- 不要使用delete來釋放不是new分配的內(nèi)存。
- 不要使用delete釋放同一個(gè)內(nèi)存塊兩次。
- 如果使用new []為數(shù)組分配內(nèi)存,則應(yīng)使用delete []來釋放。
- 如果使用new []為一個(gè)實(shí)體分配內(nèi)存,則應(yīng)使用delete(沒有方括號(hào))來釋放。
- 對(duì)空指針應(yīng)用delete是安全的。
使用動(dòng)態(tài)數(shù)組
只有把指針當(dāng)作數(shù)組名,使用索引訪問元素。原因是C和C++內(nèi)部都使用指針處理數(shù)組。
不能修改數(shù)組名的值,但指針是變量,因此可以修改指針的值。
指針、數(shù)組和指針?biāo)阈g(shù)
指針變量加1后,增加的變量等于它指向的類型的字節(jié)數(shù)。
C++將數(shù)組名解釋為指針,多數(shù)情況下,將數(shù)組名解釋為數(shù)組第一個(gè)元素的地址。
在很多情況下,可以相同的方式使用指針名和數(shù)組名。可使用數(shù)組方括號(hào)表示法,也可以使用解除引用運(yùn)算符*。在多數(shù)表達(dá)式中,它們都表地址,區(qū)別之一是,可以修改指針的指,而數(shù)組名是常量。另一個(gè)區(qū)別是,數(shù)組應(yīng)用sizeof運(yùn)算符得到的是數(shù)組的長(zhǎng)度,對(duì)指針應(yīng)用sizeof得到的是指針的長(zhǎng)度,即使指針指向的是一個(gè)數(shù)組。
這種情況下,C++不會(huì)將數(shù)組名解釋為地址。
對(duì)數(shù)組名取地址時(shí),數(shù)組名也不會(huì)被解釋為地址,這樣得到的是整個(gè)數(shù)組的地址。
指針小結(jié)
要聲明指向特定類型的指針,使用如下格式:
typeName * pointName;應(yīng)將內(nèi)存地址賦給指針,可以對(duì)變量名應(yīng)用&運(yùn)算符,來獲得被命名的內(nèi)存的地址,new運(yùn)算符返回未命名的內(nèi)存的地址。
對(duì)指針解除引用意味著獲得指針指向的值,對(duì)指針應(yīng)用解除引用或間接值運(yùn)算符*來解除引用。
另一種對(duì)指針解除引用的方法是使用數(shù)組表示法。
在多數(shù)情況下,C++將數(shù)組名視為數(shù)組的第一個(gè)元素的地址。一種情況例外是,將sizeof運(yùn)算符用于數(shù)組名時(shí),此時(shí)返回整個(gè)數(shù)組的長(zhǎng)度。
C++允許將指針與整數(shù)相加。相加的結(jié)果等于原來的地址加上指向的對(duì)象占用的總字節(jié)數(shù)。還可以兩個(gè)指針相關(guān),得到一個(gè)整數(shù),僅當(dāng)兩個(gè)指針指向同一個(gè)數(shù)組(也可以指向超出結(jié)尾一個(gè)位置)時(shí),這種運(yùn)算才有意義,這將得到兩個(gè)元素的間隔。
使用數(shù)組聲明來創(chuàng)建數(shù)組時(shí),將采用靜態(tài)聯(lián)編,即數(shù)組的長(zhǎng)度在編譯時(shí)設(shè)置。
使用new []運(yùn)算符創(chuàng)建數(shù)組時(shí),將采用動(dòng)態(tài)聯(lián)編(動(dòng)態(tài)數(shù)組),即將在運(yùn)行時(shí)為數(shù)組分配內(nèi)存,其長(zhǎng)度也在運(yùn)行時(shí)設(shè)置。使用完這種數(shù)組后,應(yīng)使用deldte []釋放其占用的內(nèi)存。
使用方括號(hào)數(shù)組表示法等同于對(duì)指針解除引用。
指針和字符串
注意:在cout和多數(shù)C++表達(dá)式中,char數(shù)組名、char指針以及用引號(hào)括起的字符串常量都被解釋為字符串第一個(gè)字符的地址。
- 有些編譯器將字符串字面值視為只讀常量,不能修改。在C++中,字符串字面值都被視為常量。
- 有些編譯器只使用字符串字面值的一個(gè)副本來表示程序中的有的該字面值。C++不能保證字符串字面值被唯一地存儲(chǔ)。
不要使用字符串常量或示被初始化的指針來接收輸入。
注意在將字符串讀入程序時(shí),應(yīng)使用已分配的內(nèi)存地址。該地址可以是數(shù)組名,也可以是使用new初始化過的指針。
strcpy()函數(shù)接受2個(gè)參數(shù),第一個(gè)是目標(biāo)地址,第二個(gè)是要復(fù)制的字符串的地址。
strncpy()函數(shù)還接受第3個(gè)參數(shù)——要復(fù)制的最大字符數(shù)。
警告:應(yīng)使用strcpy()和strncpy(),而不是賦值運(yùn)算符來將字符串賦給地址。
使用 new 創(chuàng)建動(dòng)態(tài)結(jié)構(gòu)
需要在程序運(yùn)行時(shí)為結(jié)構(gòu)分配所需的空間,也可使用new運(yùn)算符來完成,創(chuàng)建動(dòng)態(tài)結(jié)構(gòu)。由于類與結(jié)構(gòu)非常相似,所以本節(jié)有關(guān)結(jié)構(gòu)的技術(shù)也適用與類。
將new用于結(jié)構(gòu)需要兩步:創(chuàng)建結(jié)構(gòu)和訪問其成員。
要?jiǎng)?chuàng)建結(jié)構(gòu),需要同時(shí)使用結(jié)構(gòu)類型和new,將地址賦給指針。
創(chuàng)建動(dòng)態(tài)結(jié)構(gòu)時(shí),不能使用成員運(yùn)算符,因?yàn)檫@種結(jié)構(gòu)沒有名稱只有地址,C++提供了一個(gè)運(yùn)算符:箭頭成員運(yùn)算符->用于指向結(jié)構(gòu)的指針,就像點(diǎn)運(yùn)算符可用于結(jié)構(gòu)名稱一樣。
另一種訪問結(jié)構(gòu)成員的方法是,如果ps是指向結(jié)構(gòu)的指針,則*ps是被指向的值——結(jié)構(gòu)本身,因此(*ps).price是該結(jié)構(gòu)的成員。C++的運(yùn)算優(yōu)先規(guī)則要求使用括號(hào)。
自動(dòng)存儲(chǔ)、靜態(tài)存儲(chǔ)和動(dòng)態(tài)存儲(chǔ)
C++有三種管理數(shù)據(jù)內(nèi)存的方式:自動(dòng)存儲(chǔ)、靜態(tài)存儲(chǔ)和動(dòng)態(tài)存儲(chǔ)(有時(shí)也叫作自由存儲(chǔ)空間或堆)。C++11新增了第四種類型——線程存儲(chǔ)。
自動(dòng)存儲(chǔ)
在函數(shù)內(nèi)部定義的常規(guī)變量使用自動(dòng)存儲(chǔ)空間,被稱為自動(dòng)變量,在所屬的函數(shù)被調(diào)用時(shí)自動(dòng)產(chǎn)生,在該函數(shù)結(jié)束時(shí)消亡。
自動(dòng)變量是一個(gè)局部變量,其使用域?yàn)榘拇a塊。
自動(dòng)變量通常存儲(chǔ)在棧中,執(zhí)行代碼塊時(shí),其中的變量依次加入棧中,而離開代碼塊時(shí),將按相反的順序釋放這些變量,這被稱為后進(jìn)先出(LIFO)。
靜態(tài)存儲(chǔ)
靜態(tài)存儲(chǔ)是整個(gè)程序執(zhí)行期間都存在的存儲(chǔ)方式。使變量成為靜態(tài)的方式有兩種:一種是在函數(shù)外面定義它;另一種是在聲明變量時(shí)使用關(guān)鍵字static。
C++實(shí)現(xiàn)還不支持對(duì)自動(dòng)數(shù)組和自動(dòng)結(jié)構(gòu)的初始化。
動(dòng)態(tài)存儲(chǔ)
new和delete運(yùn)算符管理了一個(gè)內(nèi)存池,這在C++中被稱為自由存儲(chǔ)空間(free store)或堆(heap)。該內(nèi)存池與靜態(tài)變量和自動(dòng)變量的內(nèi)存是分開的。在棧中,自動(dòng)添加和刪除機(jī)制使得占用的內(nèi)存總是連續(xù)的,但new和delete的相互影響可能導(dǎo)致占用的自由內(nèi)存區(qū)不連續(xù)。
數(shù)組的替代品
模板類vector和array是數(shù)組的替代品。
模板類 vector
模板類vector類似于string類,也是一種動(dòng)態(tài)數(shù)組。它是使用new創(chuàng)建動(dòng)態(tài)數(shù)組的替代品,實(shí)際上vector類確實(shí)是使用new和delete來管理內(nèi)存,但其工作是自動(dòng)完成的。
首先,使用vector對(duì)象,必須包含頭文件vector。
其次,vector包含在名稱空間std中,因此要使用using編譯指令、using聲明或std::vector。
第三,模板使用不同的語(yǔ)法來指出它存儲(chǔ)的數(shù)據(jù)類型。
第四,vector類使用不同的語(yǔ)法來指定元素?cái)?shù)。
創(chuàng)建一個(gè)名為vt的vector對(duì)象,可存儲(chǔ)n_elem個(gè)類型為typeName的元素,其中參數(shù)n_elem可以是整型常量,也可以是整型變量。
模板類 array(C++11)
vector類的功能比數(shù)組強(qiáng)大,但付出的代價(jià)是效率低。如果需要長(zhǎng)度固定的數(shù)組,使用數(shù)組是更佳選擇,但代價(jià)是不那么方便和安全。
C++11新增了模板類array,它也位于名稱空間std中。與數(shù)組一樣,array對(duì)象的長(zhǎng)度也是固定,也使用棧(靜態(tài)內(nèi)存分配),而不是自由存儲(chǔ)區(qū),因此效率與數(shù)組相同,但更方便,更安全。要?jiǎng)?chuàng)建array對(duì)象,需要包含頭文件array。
創(chuàng)建一個(gè)名為arr的array對(duì)象,可包含n_elem個(gè)類型為typeName的元素,其中參數(shù)n_elem是整型常量,不可以是整型變量。
比較數(shù)組、vector 對(duì)象和 array 對(duì)象
首先,數(shù)組、vector對(duì)象和array對(duì)象,都可以使用標(biāo)準(zhǔn)數(shù)組表示法來訪問各個(gè)元素。
其次,array對(duì)象與數(shù)組存儲(chǔ)在棧中,而vector對(duì)象存儲(chǔ)在自由存儲(chǔ)區(qū)或堆中。
第三,可以將一個(gè)array對(duì)象賦給另一個(gè)array對(duì)象;而對(duì)于數(shù)組,必須逐元素復(fù)制數(shù)據(jù)。
使用中括號(hào)表示法時(shí),C++不檢查索引是否非法,而vector對(duì)象和array對(duì)象的成員函數(shù)at()將在運(yùn)行期間捕獲非法索引,而程序默認(rèn)將中斷。這種額外檢查的代價(jià)是運(yùn)行時(shí)間更長(zhǎng),這就是C++允許任何一種表示法的原因所在。它們包含成員函數(shù)begin()和end(),能夠確定邊界。
第 4 章總結(jié)
數(shù)組、結(jié)構(gòu)和指針是C++的3種復(fù)合類型。數(shù)組可以在一個(gè)數(shù)據(jù)對(duì)象中存儲(chǔ)多個(gè)同種類型的值。通過
使用索引或下標(biāo),可以訪向數(shù)組中各個(gè)元素。
結(jié)構(gòu)可以將多個(gè)不同類型的值存儲(chǔ)在同一個(gè)數(shù)據(jù)對(duì)象中,可以使用成員關(guān)系運(yùn)算符.來訪問其中的
成員。使用結(jié)構(gòu)的第一步是創(chuàng)建結(jié)構(gòu)模板,它定義結(jié)構(gòu)存儲(chǔ)了哪些成員。模板的名稱將成為新類型的標(biāo)識(shí)符,然后就可以聲明這種類型的結(jié)構(gòu)變量。
共用體可以存儲(chǔ)一個(gè)值,但是這個(gè)值可以是不同的類型,成員名指出了使用的模式。
指針是被設(shè)計(jì)用來存儲(chǔ)地址的變量。我們說,指針指向它存儲(chǔ)的地址。指針聲明指出了指針指向的對(duì)
象的類型。對(duì)指針應(yīng)用解除引用運(yùn)算符,將得到指針指向的位置中的值。
字符串是以空字符為結(jié)尾的一系列字符。字符串可用引號(hào)括起的字符串常量表示,其中隱式包含了結(jié)
尾的空字符。可以將字符串存儲(chǔ)在char數(shù)組中,可以用被初始化為指向字符串的char指針表示字符串。函數(shù)strlen()返回字符串的長(zhǎng)度,其中不包括空字符。函數(shù)strcpy()將字符串從一個(gè)位置復(fù)制到另一個(gè)位置。在使用這些函數(shù)時(shí),應(yīng)當(dāng)包含頭文件cstring或string.h。
頭文件string支持的C++strimg類提供了另一種對(duì)用戶更友好的字符串處理方法。具體地說,string對(duì)象將根據(jù)要存儲(chǔ)的字符串自動(dòng)調(diào)整其大小,用戶可以使用賦值運(yùn)算符來復(fù)制字符串。
new運(yùn)算符允許在程序運(yùn)行時(shí)為數(shù)據(jù)對(duì)象請(qǐng)求內(nèi)存。該運(yùn)算符返回獲得內(nèi)存的地址,可以將這個(gè)地址
賦給一個(gè)指針,程序?qū)⒅荒苁褂迷撝羔榿碓L問這塊內(nèi)存。如果數(shù)據(jù)對(duì)象是簡(jiǎn)單變量,則可以使用解除引用運(yùn)算符(*)來獲得其值;如果數(shù)據(jù)對(duì)象是數(shù)組,則可以像使用數(shù)組名那樣使用指針來訪問元素;如果數(shù)據(jù)對(duì)象是結(jié)構(gòu),則可以用指針解除引用運(yùn)算符->來訪問其成員。
指針和數(shù)組緊密相關(guān)。如果ar是數(shù)組名,則表達(dá)式ar[i]被解釋為*(ar+i),其中數(shù)組名被解釋為數(shù)組第一個(gè)元素的地址。這樣,數(shù)組名的作用和指針相同。反過來,可以使用數(shù)組表示法,通過指針名來訪問new分配的數(shù)組中的元素。
運(yùn)算符new和delete允許顯式控制何時(shí)給數(shù)據(jù)對(duì)象分配內(nèi)存,何時(shí)將內(nèi)存歸還給內(nèi)存池。自動(dòng)變量是在函數(shù)中聲明的變量,而靜態(tài)變量是在函數(shù)外部或者使用關(guān)鍵字static聲明的變量,這兩種變量都不太靈活。自動(dòng)變量在程序執(zhí)行到其所屬的代碼塊(通常是函數(shù)定義)時(shí)產(chǎn)生,在離開該代碼塊時(shí)終止。靜態(tài)變量在整個(gè)程序周期內(nèi)都存在。
C++98新增的標(biāo)準(zhǔn)模板庫(kù)(STL)提供了模板類vector,它是動(dòng)態(tài)數(shù)組的替代品。C++11提供了模板
類array,它是定長(zhǎng)數(shù)組的替代品。
總結(jié)
以上是生活随笔為你收集整理的C++ Primer Plus 学习笔记(第 4 章 复合类型)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: node js批量导出PDF 导出压缩为
- 下一篇: C++:[编程题]买帽子