C++primer 第 3 章 字符串、向量和數組 3 . 3 標準庫類型vector

  • 標準庫類型vector表示對象的集合,其中所有對象的類型都相同。集合中的每個對象都有一個與之對應的索引,索引用于訪問對象。因為vector"容納著”其他對象,所以它也常被稱作容器(container).第 II部將對容器進行更為詳細的介紹。 要想使用vector,必須包含適當的頭文件。在后續的例子中,都將假定做了如下using聲明:
  • #include <vector>
  • using std::vector;
  • C++語言既有類模板(classtemplate),也有函數模板,其中vector是一個類模板。只有對C++有了相當深入的理解才能寫出模板,事實上,我們直到第16章才會學習如何自定義模板。幸運的是,即使還不會創建模板,我們也可以先試著用用它。
  • 模板本身不是類或函數,相反可以將模板看作為編譯器生成類或函數編寫的一份說明。編譯器根據模板創建類或函數的過程稱為實例化(instantiation),當使用模板時,需要指出編譯器應把類或函數實例化成何種類型。
  • 對于類模板來說,我們通過提供一些額外信息來指定模板到底實例化成什么樣的類,需要提供哪些信息由模板決定。提供信息的方式總是這樣:即在模板名字后面跟一對尖括號,在括號內放上信息。

  • vector能容納絕大多數類型的對象作為其元素,但是因為引用不是對象(參見2.3.1節,第45頁),所以不存在包含引用的vectoro除此之外,其他大多數(非引用)內置類型和類類型都可以構成vector對象,甚至組成vector的元素也可以是vector。需要指出的是,在早期版本的C++標準中如果vector的元素還是vector(或者其他模板類型),則其定義的形式與現在的C++11新標準略有不同。過去,必須在外層vector對象的右尖括號和其元素類型之間添加一個空格,如應該寫成vector<vector<int> >而非vector<vector<int>>現在大可不必

3.3.1定義和初始化vector對象

  • 和任何一種類類型一樣,vector模板控制著定義和初始化向量的方法。表3.4列出了定義vector對象的常用方法。

  • 可以默認初始化vector對象(參見2.2.1節,第 40頁),從而創建一個指定類型的空 vector:
  • vector<string> svec; //默認初始化,svec不含任何元素? 最好使用空的花括號進行默認初始化?vector<string> svec{};
  • 看起來空vector好像沒什么用,但是很快我們就會知道程序在運行時可以很高效地往 vector對象中添加元素。事實上,最常見的方式就是先定義一個空vector,然后當運行時獲取到元素的值后再逐一添加。當然也可以在定義vector對象時指定元素的初始值。例如,允許把一個vector對 象的元素拷貝給另外一個vector對象。此時,新 vector對象的元素就是原vector 對象對應元素的副本。注意兩個vector對象的類型必須相同
  • vector<int> ivec; / / 初始狀態為空
  • / / 在此處給ivec添加一些值
  • vector<int> ivec2 (ivec) ; // 把 ivec 的元素拷貝給 ivec2
  • vector<int> ivec3 = ivec; // 把 ivec 的元素拷貝給 ivec3
  • vector<string> svec (ivec2) ; // 錯誤:svec 的元素是 string 對象,不是 int

列表初始化vector對象

  • C++新標準還提供了另外一種為vector對象的元素賦初值的方法,即列表初始化(參見2.2.1節,第39頁)。此時,用花括號括起來的0個或多個初始元素值被賦給vector對象
  • vector<string>articles=(”au”,"an","the'};
  • 上述vector對象包含三個元素:第一個是字符串"a",第二個是字符串"an",最后一個是字符串"the".
  • 之前已經講過,C++語言提供了幾種不同的初始化方式(參見2.2.1節,第39頁)。在大多數情況下這些初始化方式可以相互等價地使用,不過也并非一直如此。目前已經介紹過的兩種例外情況是:其一,使用拷貝初始化時(即使用=時)(參見3.2.1節,第76頁),只能提供一個初始值;其二,如果提供的是一個類內初始值(參見2.6.1節,第64頁),則只能使用拷貝初始化或使用花括號的形式初始化。第三種特殊的要求是,如果提供的是初始元素值的列表,則只能把初始值都放在花括號里進行列表初始化,而不能放在圓括號里
  • vector<string> vl { naM , "an”, "the”}; // 列表初始化
  • vector<string> v2 ("a*1, "an”, "the"); // 錯誤

創建指定數量的元素

  • 還可以用vector對象容納的元素數量和所有元素的統一初始值來初始化vector對象:
  • vector<int> ivec (10, -1) ; // 10個 int類型的元素,每個都被初始化為-1
  • vector<string> svec (10, "hi!”); // 10 個 string 類型的元素,每個都被初始化為"hi!”

值初始化

  • 通常情況下,可以只提供Vector對象容納的元素數量而不用略去初始值。此時庫會創建一個值初始化的(value-initialized)元素初值,并把它賦給容器中的所有元素。這個初值由vector對象中元素的類型決定。如果vector對象的元素是內置類型,比如int,則元素初始值自動設為0。如果元素是某種類類型,比如string,則元素由類默認初始化
  • vector<int> ivec(10);// 10個元素,每個都初始化為0
  • vector<string> svec(10);// 10個元素,每個都是空string對象
  • 對這種初始化的方式有兩個特殊限制:
  • 其一,有些類要求必須明確地提供初始值(參見2.2.1節,第40頁),如果vector對象中元素的類型不支持默認初始化,我們就必須提供初始的元素值。對這種類型的對象來說,只提供元素的數量而不設定初始值無法完成初始化工作。
  • 其二,如果只提供了元素的數量而沒有設定初始值,只能使用直接初始化
  • vector<int> vi = 10; / / 錯誤:必須使用直接初始化的形式指定向量大小
  • 這里的10是用來說明如何初始化vector對象的,我們用它的本意是想創建含有10個值 初始化了的元素的vector對象,而非把數字10 “拷貝”到 vector中。因此,此時不宜使用拷貝初始化,7.5.4節 (第 265頁)將對這一點做更詳細的介紹。

列表初始值還是元素數量?

  • 在某些情況下,初始化的真實含義依賴于傳遞初始值時用的是花括號還是圓括號。例如,用一個整數來初始化vector<int>時,整數的含義可能是vector對象的容量也可能是元素的值。類似的,用兩個整數來初始化vector<int>時,這兩個整數可能一個是vector對象的容量,另一個是元素的初值,也可能它們是容量為2的vector對象中兩個元素的初值。通過使用花括號或圓括號可以區分上述這些含義
  • vector<int> vl(10);?// vl有 10個元素,每個的值都是0
  • vector<int> v2(10};// v2有 1個元素,該元素的值是10
  • vector<int>v3(10, 1);// v3有 10個元素,每個的值都是1
  • vector<int> v4(10, 1}; // v4有 2個元素,值分別是10和 1
  • 如果用的是圓括號,可以說提供的值是用來構造(construct)vector對象的。例如,vl的初始值說明了vector對象的容量;v3的兩個初始值則分別說明了vector對象的容量和元素的初值。
  • 如果用的是花括號,可以表述成我們想列表初始化(listinitialize)該vector對象。也就是說,初始化過程會盡可能地把花括號內的值當成是元素初始值的列表來處理,只有在無法執行列表初始化時才會考慮其他初始化方式。在上例中,給v2和v4提供的初始值都能作為元素的值,所以它們都會執行列表初始化,vector對象v2包含一個元素而vector對象v4包含兩個元素。
  • 另一方面,如果初始化時使用了花括號的形式但是提供的值又不能用來列表初始化,就要考慮用這樣的值來構造vector對象了。例如,要想列表初始化一個含有string對象的vector對象,應該提供能賦給string對象的初值。此時不難區分到底是要列表初始化vector對象的元素還是用給定的容量值來構造vector對象:

  • 盡管在上面的例子中除了第二條語句之外都用了花括號,但其實只有v 5 是列表初始化。 要想列表初始化vector對象,花括號里的值必須與元素類型相同。顯然不能用int初始化string對象,所以v7 和 v8 提供的值不能作為元素的初始值。確認無法執行列表初始化后,編譯器會嘗試用默認值初始化vector對象

3.3.2向vector對象中添加元素

  • 對Vector對象來說,直接初始化的方式適用于三種情況初始值已知且數量較少、初始值是另一個vector對象的副本、所有元素的初始值都一樣。然而更常見的情況是:創建一個vector對象時并不清楚實際所需的元素個數,元素的值也經常無法確定。還有些時候即使元素的初值已知,但如果這些值總量較大而各不相同,那么在創建vector對象的時候執行初始化操作也會顯得過于煩瑣。
  • 舉個例子,如果想創建一個vector對象令其包含從0到9共10個元素,使用列表初始化的方法很容易做到這一點;但如果vector對象包含的元素是從0到99或者從0至999呢?這時通過列表初始化把所有元素都一一羅列出來就不太合適了。對于此例來說,更好的處理方法是先創建一個空vector,然后在運行時再利用vector的成員函數push_back向其中添加元素。push_back負責把一個值當成vector對象的尾元素“壓至(push)"vector對象的“尾端(back)”。例如:

  • 在上例中,盡管知道vector對象最后會包含100個元素,但在一開始還是把它聲明成空vector,在每次迭代時才順序地把下一個整數作為v2的新元素添加給它。同樣的,如果直到運行時才能知道vector對象中元素的確切個數,也應該使用剛剛這種方法創建vector對象并為其賦值。例如,有時需要實時讀入數據然后將其賦予vector對象:

  • 和之前的例子一樣,本例也是先創建一個空vector,之后依次讀入未知數量的值并保存至text 中。

向vector對象添加元素蘊含的編程假定

  • 由于能高效便捷地向vector對象中添加元素,很多編程工作被極大簡化了。然而,這種簡便性也伴隨著一些對編寫程序更高的要求:其中一條就是必須要確保所寫的循環正確無誤,特別是在循環有可能改變vector對象容量的時候。隨著對vector的更多使用,我們還會逐漸了解到其他一些隱含的要求,其中一條是現在就要指出的:如果循環體內部包含有向vector對象添加元素的語句,則不能使用范圍for循環,具體原因將在5.4.3節(第168頁)詳細解釋。
  • 范圍for語句體內不應改變其所遍歷序列的大小? ?因為vector在擴張的時候,指向最后的位置會失效,for循環找不到結束判斷條件

3.3.3其他vector操作

  • 除了push_back之外,vector還提供了幾種其他操作,大多數都和string的相關操作類似,募3.5列出了其中比較重要的一些。

  • 訪問vector對象中元素的方法和訪問string對象中字符的方法差不多,也是通過元素在vector對象中的位置。例如,可以使用范圍for語句處理vector對象中的所 有元素:

  • 第一個循環把控制變量i定義成引用類型,這樣就能通過i給V的元素賦值,其中i的類型由auto關鍵字指定。這里用到了一種新的復合賦值運算符(參見1.4.1節,第10頁)。如我們所知,+=把左側運算對象和右側運算對象相加,結果存入左側運算對象;類似的,*=把左側運算對象和右側運算對象相乘,結果存入左側運算對象。最后,第二個循環輸出所有元素。
  • vector的empty和size兩個成員與string的同名成員(參見3.2.2節,第78頁)功能完全一致:empty檢查vector對象是否包含元素然后返回一個布爾值;size則返回vector對象中元素的個數,返回值的類型是由vector定義的size_type類型。
  • 要使用size_type,需首先指定它是由哪種類型定義的、vector對象的類型總是包含著元素的類型(參見3.3節,第87頁 ):
  • vector<int>: : size_type // 正確
  • vector: :size_type // 錯誤
  • 各個相等性運算符和關系運算符也與string的相應運算符(參見3.2.2節,第79頁)功能一致。兩個vector對象相等當且僅當它們所含的元素個數相同,而且對應位置的元素值也相同。關系運算符依照字典順序進行比較:如果兩個vector對象的容量不同,但是在相同位置上的元素值都一樣,則元素較少的vector對象小于元素較多的vector對象;若元素的值有區別,則vector對象的大小關系由第一對相異的元素值的大小關系決定。只有當元素的值可比較時,vector對象才能被比較。一些類,如string等,確實定義了自己的相等性運算符和關系運算符;另外一些,如Sales_item類支持的運算已經全都羅列在1.5.1節(第17頁)中了,顯然并不支持相等性判味和關系運算等操作。因此,不能比較兩個vector<Sales_item>對象。

計算vector內對象的索引

  • 使用下標運算符(參見323節,第84頁)能獲取到指定的元素。和string-樣,vector對象的下標也是從0開始計起,下標的類型是相應的size_type類型。只要vector對象不是一個常量,就能向下標運算符返回的元素賦值。此外,如3.2.3節(第85頁)所述的那樣,也能通過計算得到vector內對象的索引,然后直接獲取索引位置上的元素。
  • 舉個例子,假設有一組成績的集合,其中成績的取值是從0到100。以10分為一個分數段,要求統計各個分數段各有多少個成績。顯然,從0到100總共有101種可能的成績取值,這些成績分布在11個分數段上:每10個分數構成一個分數段,這樣的分數段有10個,額外還有一個分數段表示滿分100分。這樣第一個分數段將統計成績在0到9之間的數量;第二個分數段將統計成績在10到19之間的數量,以此類推。最后一個分數段統計滿分100分的數量。
  • 按照上面的描述,如果輸入的成績如下:42 65 95 100 39 67 95 76 88 76 83 92 76 93
  • 則輸出的結果應該是:0 0 0 1 1 0 2 3 2 4 1
  • 結果顯示:成績在30分以下的沒有、30分至39分有1個、40分至49分有1個、50分至59分沒有、60分至69分有2 個、70分至79分有3 個、80分至89分有2 個、90分至99分有4 個,還有1個是滿分。在具體實現時使用一個含有11個元素的vector對象,每個元素分別用于統計各個分數段上出現的成績個數。對于某個成績來說,將其除以10就能得到對應的分數段索引。
  • 注意:兩個整數相除,結果還是整數,余數部分被自動忽略掉了。例如,42/10=4、65/10=6、100/10=10等。一旦計算得到了分數段索引,取該分數段的計數值并加1:就能用它作為vector對象的下標,進而獲取該分數段的計數值并加1:

  • 在上面的程序中,首先定義了一個Vector對象存放各個分數段上成績的數量。此例中,由于初始狀態下每個元素的值都相同,所以我們為vector對象申請了11個元素,并把所有元素的初始值都設為0。while語句的條件部分負責讀入成績,在循環體內部首先檢查讀入的成績是否合法(即是否小于等于100分),如果合法,將成績對應的分數段的計數值加1。
  • 執行計數值累加的那條語句很好地體現了C++程序代碼的簡潔性。

不能用下標形式添加元素

  • 剛接觸C++語言的程序員也許會認為可以通過vector對象的下標形式來添加元素, 事實并非如此。下面的代碼試圖為vector對象ivec添加10個元素:
  • vector<int> ivec; // 空 vector 對象

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446668.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446668.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446668.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringBoot AOP切面實現

文章目錄一、AOP簡介二、AOP體系與概念三、AOP實例1、創建SpringBoot工程2、添加依賴3、AOP相關注解3.1、Aspect3.2、Pointcut3.2.1、execution()3.2.2、annotation()3.3、Around3.4、Before3.5、After3.6、AfterReturning3.7、AfterThrowing一、AOP簡介 AOP&#xff08;Aspec…

英語口語-文章朗讀Week8 Friday

文章 It is a phenomenon that people are losing trust in each other in today’s society. Some people become selfish,and for interest, they are likely to betray their colleagues,friends, and even their relatives. They tend to cater to those who can benefit …

C++primer 第 3 章 字符串、向量和數組 3 . 4 迭代器介紹

3.4迭代器介紹 我們已經知道可以使用下標運算符來訪問string對象的字符或vector對象的元素&#xff0c;還有另外一種更通用的機制也可以實現同樣的目的&#xff0c;這就是迭代器&#xff08;iterator&#xff09;。在第II部分中將要介紹&#xff0c;除了vector之外&#xff0c…

ClickHouse 函數

文章目錄一、日期函數1、時間或日期截取函數&#xff08;返回非日期&#xff09;2、時間或日期截取函數&#xff08;返回日期&#xff09;3、日期或時間日期生成函數二、類型轉化類函數1、精度保留&#xff08;非四舍五入&#xff09;2、字符串轉化為整數&#xff08;非整數的字…

英語口語-文章朗讀Week9 TuesDay

朗讀文章 People living in ancient times had no alternative but to do housework manually. They fire the wood when they cook,they hand wash clothes with hands; they sweep the floor with brooms. Now, modern inventions come as a great relief to people. We co…

SpringBoot @Value注解

目錄一、非配置文件注入1、注入普通字符串2、注入JAVA系統變量3、注入表達式4、注入其他Bean屬性5、注入文件資源6、注入URL資源二、通過配置文件注入1、注入普通字符串2、注入基本類型3、注入數組類型4、注入List類型5、注入Map類型一、非配置文件注入 1、注入普通字符串 直…

C++primer 第 3 章 字符串、向量和數組 3 . 5 數組

3.5數組 數組是一種類似于標準庫類型vector&#xff08;參見3.3節&#xff0c;第86頁&#xff09;的數據結構&#xff0c;但是在性能和靈活性的權衡上又與vector有所不同。與vector相似的地方是&#xff0c;數組也是存放類型相同的對象的容器&#xff0c;這些對象本身沒有名字…

codeforces 122A-C語言解題報告

122A題目網址 題目解析 1.輸入數字(在1000以內),若能被4,7幸運數整除或只含4,7則輸出YES,否則輸出NO 舉例: 輸入: 107 輸出: NO 2.解題關鍵: 1)使用列舉法,把所有符合的幸運數列出來(int number[]) 1—2 2–224 3–22*28 24814個 2)若n是幸運數中的一個或n%幸運數0,則為YES…

SpringBoot @Value給靜態變量注入值

文章目錄一、簡介二、Value給靜態變量注入值方案一&#xff1a;set()方法設置方案二&#xff1a;PostConstruct注解修飾的方法中進行賦值三、總結一、簡介 SpringBoot 中給普通變量注入值只需在變量上添加 Value 注解即可。 application.properties 配置文件有如下配置&#…

C++primer 第 4 章 表達式 4.1基礎 4 . 2 算術運算符 4 .3 邏輯和關系運算符 4 . 4 賦值運算符 4 .5 遞增和遞減運算符 4.6成員訪問運算符

表達式由一個或多個運算對象(operand)組成&#xff0c;對表達式求值將得到一個結果(result)字面值和變量是最簡單的表達式(expression),其結果就是字面值和變量的值。把一個運算符(operator)和一個或多個運算對象組合起來可以生成較復雜的表達式 4.1基礎 有幾個基礎概念對表達…

codeforces 266B-C語言解題報告

266B題目網址 題目解析 輸入n,t,排隊情況s,輸出第t次循環后,排隊情況 舉例: 輸入: 5 1 BGGBG 輸出: GBGGB 2.輸入的n代表排隊的人數,t代表整個循環t次之后再輸出結果 3.注意點: 使用while()大循環去控制t次的循環,使用for()內層循環去遍歷整個字符串 如果if(s[j]‘B’&…

Nginx Location配置詳解

目錄一、語法二、匹配順序三、root 與 alias 的區別四、server 和 location 中的 root一、語法 Location 是 Nginx 中一個非常核心的配置&#xff0c;關于Location&#xff0c;舉個簡單的配置例子&#xff1a; server {listen 80;server_name 10.0.7.115;location / {root /d…

英語口語-文章朗讀Week9 Wednesday

英語文章 Birds of the same species flock together&#xff0c; People tend to look for someone like themselves to be friends. But having the same interests is not the only standard when we are seeking friends. In most cases, especially for adults, people l…

C++primer 第 4 章 表達式 4.7條件運算符 4.8位運算符 4.9 sizeof運算符 4.10逗號運算符 4.11類型轉換 4 . 1 2 運算符優先級表

4.7條件運算符 條件運算符(?&#xff1a;)允許我們把簡單的if else邏輯嵌入到單個表達式當中&#xff0c;條件運算符按照如下形式使用&#xff1a;cond ? expr1 : expr2;其中cond是判斷條件的表達式&#xff0c;而expr1和expr2是兩個類型相同或可能轉換為某個公共類型的表達…

Git 之 git tag標簽使用

目錄一、簡介二、本地tag操作1、創建tag標簽&#xff08;1&#xff09;創建輕量標簽&#xff08;2&#xff09;創建附注標簽2、查看tag標簽&#xff08;1&#xff09;查看標簽列表&#xff08;2&#xff09;查看標簽提交信息&#xff08;3&#xff09;在提交歷史中查看標簽3、刪…

codeforces 110A-C語言解題報告

110A題目網址 題目解析 1.輸入一個數字,如果數字中包含的4,7的數量是4或7的倍數,則輸出YES,否則輸出NO 舉例: 輸入: 40047 輸出: NO 2.注意點: 1)由于數字很長,所以使用long long int類型,使用scanf("%lld",&n)接收輸入 2)整型轉字符串,使用sprintf(字符串,“…

C++primer 第 5 章語句 5.2語句作用域 5.3條件語句 5 . 4 迭代語句 5.5跳轉語句 5.6 try語句塊和異常處理

5 . 1 簡單語句 C語言中的大多數語句都以分號結束&#xff0c;一個表達式&#xff0c;比如ival 5 , 末尾加上分號就變成了表達式語句(expression statement)。表達式語句的作用是執行表達式并丟棄掉求值結果&#xff1a;ival 5&#xff1b; // 一條沒什么實際用處的表達式語…

英語口語-文章朗讀Week9Thursday

英語文章 Everyone has his or her own dreams. Some people wants to be millionaires so they can give many generous donations later; some people want to be scientists so they can bring many conveniences to the world; some people only want to be bus-drivers s…

操作系統 內存管理相關知識

cpu執行程序的基本過程 譯碼器 輸入為n管腳&#xff0c;輸出為2^n根管腳&#xff0c;編號為從0到2^(n-1)&#xff0c;用少的輸入端控制更多的輸出端最常用的是三八譯碼器AD(Address bus)地址總線: 選中一行數據每一行 8bit 組成8吧B cpu輸入端32根線&#xff0c;輸出端就可以控…

2000年考研英語閱讀理解文章四

文章詳細解析網址 注意點 1.注意But,however等表示觀點看法轉折的詞語 2.全篇都在提及moral decline 道德下降,最后一段寫that may have more to do with life-style所以造成現象的原因應該是life-style.(主要) 前面都是在分析,最后一段點名原因 知識點 ----單詞 envy n/v…