C++ Primer Plus 第四章之C++ Primer Plus復合類型學習筆記
1. 數組概述
1.1 數組的定義
數組(array)是一種數據格式,能夠存儲多個同類型的值。每個值都存儲在一個獨立的數組元素中,計算機在內存中依次存儲數組的各個元素。
數組聲明的三個特點:
- 存儲在每個元素中的值的類型
- 數組名
- 數組中的元素數
C++中可以通過修改簡單變量的聲明,添加中括號(其中包含元素數目)來完成數組聲明。
例如:
short days[24]; // 一天有24個小時
1.2 數組的聲明
聲明數組的的一般語法格式為:
// 數組類型 數組名字[數組的大小] int score[4]; // 四個人的分數,整型數組
數組的大小是指定元素的數目,必須是整型常數或const值,也可以是常量表達式(8*sizeof(int))
1.3 復合類型的數組
可以使用其他的類型來創(chuàng)建(C語言使用術語:派生類型)
數組的用途,可以單獨訪問數組元素,方法是:使用下標或索引對元素進行編號。從0開始編號。
編譯器不會檢查下標是否有效,所以要注意下標合法性,避免程序異常問題。
C++使用索引的方括號表示法來指定數組元素。
1.4 數組的初始化規(guī)則
1.只有在定義數組時才能初始化,此后不能使用,也不能將一個數值賦給另一個數組。
2.初始化數組時,提供的值少于數組的元素數目。
3.如果只對數組的一部分進行初始化,則編譯器把其他元素設置為0。
4.如果初始化為{1}而不是{0},則第一個元素被設置為1,其他元素都被設置為0.
5.如果初始化數組方括號內([])為空,C++編譯器將計算元素個數。 例如:short things[] = {1,3,5,7};
1.5 C++11數組初始化方法
C++11將使用大括號的初始化(列表初始化)作為一種通用的初始化方式,可用于所有類型。
在C++中列表初始化就增加了一些功能:
初始化數組時,可省略等號(=)
double earnings[4] {1.2e4,1.6e4,1.1e4,1.7e4};
可不在大括號內包含任何東西,這會將所元素都設置為零。
unsigned int const[10] = {};
float balances[100] {};
列表初始化禁止縮窄轉換。
long num[] = {25,92,3.0}; // 浮點數轉換為整型是縮窄操作
例子:
#include<iostream>
using namespace std;
int main()
{
// 創(chuàng)建一個名字為yams的數組,包含了3個元素,編號是0~2.
int yams[3];
yams[0] = 7;
yams[1] = 8;
yams[2] = 6;
// 使用逗號分隔的值列表(初始化列表),然后用花括號括起來即可。
// 列表中的空格是可選的,如果沒有初始化函數中定義的數組,其元素值也是不確定。
int yamcosts[3] = {1,2,3};
cout<<"yams 數組是:"<<yams[0]+yams[1]+yams[2]<<endl;
cout<<"yams[1] = "<<yams[1]<<endl;
int total = yams[0] * yamcosts[0] + yams[1] * yamcosts[1];
total = total + yams[2] * yamcosts[2];
cout<<"total yam = "<<total<<endl;
// sizeof運算符返回類型或數據對象的長度(單位為字節(jié))。
// 如果將sizeof運算符用于數組名,得到的是整個數組的字節(jié)數。
// 如果sizeof用于數組元素,得到的是元素的長度(單位為字節(jié))。
cout<<"\n yams數組的大小 = "<<sizeof(yams)<<" Bytes.\n";
cout<<"一個元素的大小 = "<<sizeof(yams[0])<<" Bytes.\n";
return 0;
}
2. 字符串
字符串是存儲在內存的連續(xù)字節(jié)中的一系列字符。
2.1 C++處理字符串的兩種方式:
C語言,常常被稱為C-風格字符串(C-style String)
以空字符(\0,ASCII碼對應為0)來標記字符串的結尾。
基于String類庫的方法
存儲在連續(xù)字節(jié)中的一系列字符意味著可以將字符串存儲在char數組中。其中每個字符都位于自己的數組元素中。
使用引號括起來的字符串,這種字符串叫 字符串常量(String constant) 或 字符串字面值(string literal) 。
字符串常量(使用雙引號)不能與字符常量(使用單引號)互換。
例如:
char name[] = "Soler";
字符串結尾的空字符,不用直接顯式包括,機器在鍵盤輸入,將字符串讀入到char類型中,會在結尾自動加上空字符。
⚠️注意:確定了存儲字符串所需的最短數組時,不要忘記把結尾的空字符包括在內。
2.2 字符串常量的拼接
方法:直接兩個引號括起來的字符串合并為一個。任何兩個由空白(空格、制表符和換行符)分隔的字符串常量都將自動拼接成一個。
cout<<"My name is " "Soler HO.\n"
2.3 在數組中使用字符串
將字符串存儲到數組的常用方法:
- 將數組初始化為字符串
- 常量將鍵盤或文件輸入讀入到數組中。
#include <iostream>
#include <cstring> /*提供strlen()函數*/
using namespace std;
const int Size = 15;
int main()
{
char name1[Size];
char name2[Size] = "C++owboy";
// 字符串的拼接
cout<<"Howdy!I'm "<< name2;
cout<<"!,What's your name?\n";
cin>>name1;
cout<<"Well, "<<name1<<",your name has : "<<strlen(name1)<<" letters and is stored!\n" ;
cout<<"In an array of "<<sizeof(name1)<<" Bytes\n";
cout<<"Your iniatial is "<<name1[0]<<".\n"; // name1數組中的第一個元素
name2[3] = '\0';
cout<<"Here are the first 3 characters of my name:"<<name2<<endl;
return 0;
}
strlen() 函數 和 sizeof()運算符的區(qū)別
strlen()函數
返回的是存儲在數組中的字符串的長度,而~~不是數組本身的長度~~。strlen()只計算可見的字符,而不把空字符計算在內。
sizeof() 運算符
指出變量或數據類型的字節(jié)大小??捎糜讷@取類、結構、共用體和其他用戶自定義數據類型的大小。
2.4 讀取一行字符串的輸入
解決沒有逐行讀取輸入的缺陷。
istream中提供了面向行的類成員函數:getline() 和 get() 函數
2.4.1 面向行的輸入:getline()
使用通過回車鍵輸入的換行符來確定輸入結尾。使用 cin.getline() 。
函數有兩個參數:
- 第一個參數:存儲輸入行的
數組名稱。 - 第二個參數:要讀取的字符數(注意包含結尾的
空字符(\0))。
格式:
cin.getline(name,ArSize);
2.4.2 面向行的輸入:get()
與getline() 函數類似,接受的參數相同,解釋參數的方式也相同,并讀到行尾。
區(qū)別:get() 讀取并丟棄換行符,將其留在輸入隊列中。
格式:
cin.get(name,ArSize);
get() 將兩個類成員函數拼接(合并):
cin.get(name,ArSize).get();
⚠️注意:get() 函數讀取空行后設置會失效,輸入會被阻斷??捎萌缦禄謴停?/p>
cin.clear();
混合輸入數字和面向行的字符串會導致的問題:無法輸入地址。
解決方法:直接使用get()進行讀取之前丟棄換行符。
3. string類
string類位于名稱空間std中,所以需要提供using指令或者是直接使用std::string進行引用。
要使用string類,必須在程序中包含頭文件string中。
string類定義隱藏了字符串的數組性質。
3.1 string對象的方式
使用string對象的方式和使用字符數組相同。
C-風格字符串來初始化string對象中。- 使用
cin來將鍵盤輸入存儲到string對象中。 - 使用
cout來顯示string對象。 - 可以使用
數組表示方法來訪問存儲在string1對象中的字符。
賦值 —— 不能將一個數組賦給另一個數組,但可以將一個string對象賦另一個string對象。
char char01[20]; // 創(chuàng)建一個空列表 char char02[20] = "Jason"; // 創(chuàng)建一個初始化數組 string str01; // 創(chuàng)建一個空的string對象 string str02 = "Soler Ho"; // 創(chuàng)建一個初始化的string對象 char01 = char01; // 不可執(zhí)行,一個數組不能賦值給另一個數組 str01 = str02; // 可執(zhí)行,可將一個string對象賦給另一個string對象。
3.2 復制、拼接和附加
string類簡化字符串合并操作。
利用運算符 + 將兩個string對象合并起來。
string str01; string str02 = "Soler Ho"; string = str01 + str02;
可以使用運算符 += 將字符串附加到string對象的末尾。
string str01; string str02 = "Soler Ho"; str01 += str02;
4. 結構簡介
結構是用戶定義的類型,而結構聲明定義了類型的數據屬性。
定義類型之后,就直接創(chuàng)建類型的變量。
結構比數組靈活,同一個結構中可以存儲多種類型的數據。
4.1 創(chuàng)建結構的步驟:
- 定義結構描述 —— 描述并標記能夠存儲在結構中的各種數據類型
- 按描述創(chuàng)建結構變量(結構數據對象)。
4.2 結構的定義:
struct(關鍵字) 類型名(標記成為新類型的名稱)
{
結構成員1;
結構成員2;
結構成員3;
};//(結束結構聲明)
對于結構中的成員,使用成員運算符(.)來進行訪問各個成員。
4.3 結構的初始化(C++11)
與數組一樣,列表的初始化用于結構,且等號(=)可有可無。
infor Soler_infor {"Soler HO",55,168}; // 在C++11中,= 號可以省略
如果大括號內未包含任何東西,各個成員都將設置為零。
infor Soler_infor {};
不允許縮窄轉換
✅ 小Tips:C++允許在聲明結構變量時省略關鍵字struct。
4.4 成員賦值
成員賦值(memberwise assignment):可以使用賦值運算符(=)將結構賦另一個同類型的結構。這樣結構中的每個成員都將被設置為另一個結構中相應成員的值。即使成員是數組。這種方式就是成員賦值。
5. 共用體
共用體(union),也叫做聯合(union)。一種 構造數據類型 。
關鍵字:union
聯合(union):將不同類型的數據在一起共同占用同一段內存
存儲不同的數據類型,但只能同時存儲其中的一種類型
示例:
union sample
{
int int_val;
long long_val;
double double_val;
};
5.1 結構體和共用體的區(qū)別
- 結構可以
同時存儲int、long和double。 - 共用體
只能存儲int、long和double三種。 - 含義不同。
- 關鍵字不同
結構體:struct
共用體:union
5.2 共用體的用途:
- 當數據使用兩種格式或更多格式(但不會同時使用)時,可以節(jié)省空間。
- 嵌入式系統(tǒng)編程(如控制烤箱、MP3播放器),內存非常寶貴。
常用于操作系統(tǒng)數據結構或硬件數據結構。
5.3 匿名共用體
匿名共用體(anonymous union)沒有名稱,其成員將成為位于相同地址處的變量。
6. 枚舉
C++的enum工具提供了另一種創(chuàng)建符號常量的方式,可以代替const,允許定義新類型,但必須有嚴格限制。
使用enum的語法格式與結構的使用類似。
enum color{red,orange,yellow,green,blue,voilet};
6.1 設置枚舉量的值
enum week{Monday = 1,Tuesday = 2;Wednesday = 3;Thursday = 4};
指定的值必須是整數。也可以只顯示定義其中一些枚舉量的值。
如果第一個變量未初始化,默認為0。后面沒有被初始化的枚舉量的值將比其前面的枚舉量大1。也可以創(chuàng)建多個值相同的枚舉量。
enum {zero,null = 0,numero_one,one = 1};
6.2 枚舉的取值范圍
每個枚舉都有取值范圍的上限,通過強制類型轉換,可以將取值范圍中的任何整數值賦給枚舉常量,即使這個值不是枚舉值。
6.3 取值范圍的定義
- 找出上限,需要知道枚舉量的最大值。
找到大于最大值的,最小的2的冪,減去1,得到就是取值范圍的上限。
- 計算下限,知道枚舉量的最小值。
如果不小于0,則取值范圍的下限為0,否則,采用尋找上限方式相同的方式,但是要加上負號。
對于選擇使用多少空間來存儲枚舉由編譯器決定。
7. 指針和自由空間
對于地址顯示結果是十六進制表示法,因為都是常常描述內存的表示法。
指針與C++基本原理
面向對象編程和傳統(tǒng)的過程性編程的區(qū)別,OOP強調的是運行階段(而不是編譯階段)進行決策。
運行階段:程序正在運行是,取決于不同的情況。編譯階段:編譯器將程序組合起來時。堅持原先設定的安排
指針用于存儲值的地址。指針名表示的是地址。
*運算符稱為間接值或解除引用運算符,將其應用于指針,得到該地址處存儲的值。
7.1 聲明和初始化指針
指針的聲明必須指定指向的數據的類型。
int *p_updates;
*p_updates 的類型是int,所以*運算符被用于指針,所以p_updates變量必須是指針。
運算符*兩邊的空格是可選的。
int *ptr; /*該情況強調:*ptr是一個int類型的值。*/ int* ptr; /*該情況強調:int* 是一種類型,指向int的指針。*/
在C++中,int*是一種復合類型,是指向int的指針。
double *tax_ptr;
7.2 指針的危險
在C++創(chuàng)建指針時,計算機將分配用來存儲地址的內存,但是不會分配用來存儲指針所指向的數據的內存。
⚠️注意:一定要在對指針應用解除引用運算符(*)之前,將指針初始化為一個確定的、適當的地址。
7.3 指針和數字
整數可以加減乘除等運算,而指針描述的是位置。
C++語言數字不能作為地址使用,如果要把數字當地址來使用,應通過強制類型轉換將數字轉換為適當的地址類型。
7.4 使用new分配和delete釋放內存
指針在運行階段 分配未命名的內存以存儲值。然后使用內存來訪問內存。
C語言中,使用 庫函數malloc()來分配內存。C++中使用 ———— new運算符。
7.4.1 要注意使用delete進行內存的釋放
需要內存時,直接使用new來請求,這是內存管理數據包的一個方面。
如果使用了delete運算符,使得在使用完內存后,能夠將其歸還給內存池,這是有效使用內存的關鍵。
使用delete時,后面要加上指向內存塊的指針。
int * ps = new int; // 使用new進行內存分配 ... delete ps; // 使用delete進行內存的釋放
⚠️注意點:
1.使用delete釋放ps的內存,但是不會刪除指針ps本身。
2.只能用delete來釋放使用new分配的內存,但是如果是空的指針使用delete是安全的。
使用delete的關鍵:用于new分配的內存。不是要使用于new的指針,而是用于new的地址。
❌警告:不能創(chuàng)建兩個指向同一個內存塊的指針。會增加錯誤地刪除同一個內存塊兩次的可能性。
7.5 使用new創(chuàng)建動態(tài)數組
C++中,創(chuàng)建動態(tài)數組,只需要將數組的元素類型和元素數目告訴new即可。必須在類型名后面加上方括號,其中包含了元素數目。
通用格式:
Type_name *pointer_name = new Type_name[num_element]; //例子 int * psome =new int[10]; // 創(chuàng)建10個int元素的數組
new運算符會返回第一個元素的地址
如果使用完new分配的內存,使用delete進行內存的釋放。
delete [] psome; // 進行內存的釋放
delete和指針直接的方括號告訴程序,應釋放整個數組,不僅僅是指針指向的元素。
delete中的方括號的有無取決于使用new時的方括號有無。
對于指針數組的使用,直接可以按照普通數組的使用即可。
7.6 使用new和delete時,要遵循的規(guī)則
- 不要使用delete來釋放不是new分配的內存。
- 不要使用delete釋放同一個內存塊兩次。
- 如果使用new[]為數組分配內存時,則應使用delete[]來釋放。
- 如果使用new[]為一個實體分配內存,則應使用delete(沒有方括號)來釋放。
- 對空指針使用delete時很安全。
8. 指針、數組和指針算術
指針和數組基本等價的原因:指針算術(pointer arithmetic) 和C++ 內部處理數組的方式。
對整數變量 + 1,其值增加1
對指針變量 + 1,增加的量等于它指向的類型的字節(jié)數。
獲取數組地址的兩種方式
double * pw = wages; // 數組名 = 地址 ;將pw聲明為指向double類型的指針。然后將其初始化為wages - - - wages數組中第一個元素的地址。 short * ps = &wages[0]; // 使用地址操作;使用地址運算符來將ps指針初始化為stacks數組的第一個元素。
8.1 指針問題小結
8.1.1 聲明指針
要聲明指向特定類型的指針,語法格式:
TypeName *pointerName; // 例子 double * pn; // pn 指向一個double類型 char * ps; // ps 指向一個char類型
8.1.2 給指針賦值
將內存地址賦給指針??梢詫ψ兞棵麘?& 運算符,來獲得被變量名的內存地址,new運算符返回未命名的內存的地址。
示例:
double * pn; // pn 指向一個double類型 double * pa; // pa 指向一個double類型 char * pc; // pc 指向一個char類型 double bubble = 3.2; pn = &bubble; // 把bubble的地址賦值給 pn pc = new char; // 新建char地址并分配給pc
8.1.3 對指針解除引用
對指針解除引用意味著獲得指針指向的值。
方法1:對指針應用解除引用或間接值運算符(*)來解除引用。
cout<<*pn; *pc = 's';
方法2:使用數組表示法。不可以對未初始化為適當地址的指針解除引用。
8.1.4 數組名
多數情況下,C++將數組名視為數組的第一個元素的地址。
int tacos[10]; // 此時的tacos同樣也是&tacos[0]
8.1.5 指針算術
C++中允許指針和整數相加。加1 的結果等于原來的地址值加上指向的對象占用的總字節(jié)數。
也可以將一個指針減去另一個指針,獲得兩個指針的差。得到一個整數,僅當兩個指針指向同一個數組(也可以指向超出結尾的一個位置)時,這種情況會得到兩個元素的間隔。
8.1.6 數組的動態(tài)聯編和靜態(tài)聯編
使用數組聲明來創(chuàng)建數組時,將采用靜態(tài)聯編,即數組長度在編譯時設置。
int tacos[10] // 靜態(tài)聯編
使用new[]運算符創(chuàng)建數組時,將采用動態(tài)聯編(動態(tài)數組),即將在運行時為數組分配空間,其長度為運行時設置。
使用這類數組后,要使用delete[]釋放所占用的內存。
8.1.7 數組表示法和指針表示法
使用方括號數組表示法等同于對指針解除引用。
數組名和指針變量也是一樣。所以對于指針和數組名,既可以使用指針表示法,也可以使用數組表示法。
int * pt = new int [10]; *pt = 5; pt[0] = 6; pt[9] = 5; int coats[10]; *(coats + 4) = 12;
8.2 指針和字符串
數組名是第一個元素地址。
如果給cout提供一個字符的地址,則它將從該字符開始打印,直到遇到空字符為止。
在cout和多數C++表達式中,char數組名、char指針以及用引號括起來的字符串常量都被解釋為字符串第一個字符的地址。
不要使用字符串常量或未被初始化的指針來接收輸入。
在字符串讀入程序時,應使用已分配的內存地址。該地址不是數組名,也可以使用new初始化過的指針。
strcpy()接受兩個參數,第一個:目標地址,第二個:要復制的字符串的地址。
要確定目標空間有足夠的空間來存儲副本。
8.3 使用new創(chuàng)建動態(tài)結構
對于在指定結構成員時,句點運算符和箭頭運算符的選擇時:
- 如果結構標識符是
結構名,則使用句點運算符(.)。 - 如果標識符是
指向結構的指針,則使用箭頭運算符(->)。
把new用于結構的兩個步驟
創(chuàng)建結構
要創(chuàng)建結構,需要同時使用結構類型和new。
創(chuàng)建訪問其成員。
8.4 C++管理數據內存的方式自動存儲
在函數內部定義的常規(guī)變量使用自動存儲空間,稱為自動變量。
只在特定函數被執(zhí)行時存在。
自動變量時一個局部變量,作用域為包含它的代碼塊。通常存儲在棧中,遵循后進先出(LIFO)。
- 靜態(tài)存儲
變量稱為靜態(tài)的方式在函數外面定義在聲明變量時使用關鍵字static。
整個程序執(zhí)行期間都存在的存儲方式(存在于程序的整個生命周期)。
- 動態(tài)存儲
內存池(自由存儲空間或堆)用于靜態(tài)變量和自動變量,且內存是分開的。
- 線程存儲(C++11特性)
9. 數組替代品 --- 模板類
模板類vector和array是數組的替代品。
9.1 模板類vector
模板類vector類似于string類,也是一種動態(tài)數組。
vector對象包含在vector頭文件中。- vector包含在名稱空間std中,使用
using編譯指令、using聲明或std::vector。 - 模板使用不同的
語法來指出它存儲的數據類型。 - vector類使用不用的語法來指定
元素數。
9.2 模板類array(C++11)
位于名稱空間std中,與數組一樣,array對象的長度固定,也使用棧(靜態(tài)內存分配),而不是自由存儲區(qū)。
頭文件 array。
9.3 數組、vector和array的區(qū)別
無論是數組、vector對象還是array對象,都可使用標準數組表示法來訪問各個元素。
從地址可知,array對象和數組存儲在相同的內存區(qū)域(即棧)中,vector對象存儲在自由存儲區(qū)域或堆中。
可以將一個array對象賦給另一個array對象,對于數組,必須逐個元素復制數據。
Github地址:https://github.com/SolerHo/cpp-Primer-Plus-6e-Notes/blob/master/Chapter04/README.md
到此這篇關于C++ Primer Plus 第四章之C++ Primer Plus復合類型學習筆記的文章就介紹到這了,更多相關C++ Primer Plus復合類型內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

