第3章 標準庫類型

3.1、命名空間的using聲明

    在頭文件中必須總是使用完全限定的標準庫名字(即如std:cin)。因爲如果在頭文件中放置using聲明,就相當於在包含該頭文件的每個程序中都放置了同一using聲明,不論該程序是否需要using聲明。頭文件中應該只定義確實必要的東西。

3.2、標準庫string類型

3.2.1、string對象的定義和初始化

四種初始化方式:(1)strings1;默認構造函數,s1爲空串;(2)strings2(s1);將s2初始化爲s1的一個副本;(3)string s3(“value”);將s3初始化爲一個字符串字面值副本;(4)strings4(n,’c’);將s4初始化爲字符’c’的n個副本。

string s3("nnn");

string s4(3,'n');//兩者均與nnn進行==比較,結果是1char a[4] = {'n','n','n'};也是1。用char[4]會在nnn後面自動補’\0’,如果設成char[3]後面會跟亂碼。上述比較與java有區別(java有字符串常量和字符串變量之分,new出來的就不會跟常量相等,而且char[]不能與String比較)···

    由於歷史原因以及爲了與C語言兼容,字符串字面值與標準庫string類型不是同一種類型。

3.2.2、string對象的讀寫

cin>>s;從標準輸入讀取string,並存入s中,讀取特點有:(1)讀取並忽略開頭所有的空白字符(如空格、換行符、製表符);(2)讀取字符直至再次遇到空白字符,讀取終止。

    對於讀入未知數目的string對象,用while(cin>>s){···}達到文件尾則跳出循環。

    用getline讀取整行文本。該函數接受兩個參數:一個輸入流對象和一個string對象。getline函數從輸入流的下一行讀取,並保存到string中,但不包括換行符。並且它與cin不同,不忽略開頭的換行符。如果第一個就是換行符,則getline的string被置爲空。如while(getline(cin,s)){···}。java是s=bufferedReader.readLine();方法不用傳參數~。

3.2.3、string對象的操作

    c++是size求字符個數(不考慮末尾的‘\0’字符,"nnn\0"這樣長度還是3)(java是length()方法,"nnn\0"這樣長度是4)。s.empty()表示如果s爲空串,則返回true,否則返回false。

    size()操作返回的是string::size_type類型的值,它定義爲與unsigned型具有相同的含義並且可以保證足夠大能存儲任意string對象的長度。用法如:string::size_type m = s3.size();任何存儲string的size操作結果的變量必須爲string::size_type類型,而不要將返回值賦給int變量(防溢出)。

       兩個string對象相等(==)是指他們的長度相同且含有相同的字符(java的==判斷字符串是判斷是否是引用同一個內容,而new出來的,長度字符都相等也顯示false,得用equal)。(<、<=、>、>=)比較策略:(1)如果兩個string對象長度不同且短的和長的字符對象前面部分匹配,則長的string對象長;(2)如果兩個string對象的字符不同,則比較第一個不匹配的字符。

       string對象的賦值(=,如st1 = st2)所做的工作必須先把st1佔用的相關內存釋放掉,然後再分配給st1足夠存放st2副本的內存空間,最後把st2中的所有字符複製到新分配的內存空間。

       string對象相加(+、+=)用於連接兩字符串,也可以將string對象和字符串字面值(就是字符串常量,直接顯示”字符串內容”)混合連接得到同樣的結果。string s = “hi”+”,”+s1是錯誤的,第一個“+”表達式將兩個字面值連接起來,這是不允許的。而string s = s1+”hi”+”,”則是對的,因爲事實上後一個加的前面是string tmp = s1+”hi”,並不是字符串字面值。

       string對象的下標從0開始(嘗試),如string str(“some”);str[0]爲s。可以像str[0] = '*';將第一個字符串元素賦值爲別的。任何可產生整數值的表達式都可用做下標操作符的索引,如str[1*2] = ‘*’將第三個元素賦爲*。

3.2.4、string對象中字符的處理

       對string對象中的單個字符進行處理(是否爲空白符、字母、數字等),這些函數在cctype頭文件中定義。可打印的字符是指那些可以顯示錶示的字符;空白字符表示空格、製表符、垂直製表符、回車符、換行符和進紙符的任意一種;標點符號表示除了數字、字母或空白字符以外的其他可打印字符。C標準庫中有ctype.h頭文件。

3.3、標準庫vector類型

#include<vector>

using std::vector;

vector是類模板。

3.3.1、vector對象的定義和初始化

    構造函數:(1)vector<T> v1;vector保存類型爲T的對象。默認構造函數,v1爲空;(2)vector<T> v2(v1);v2是v1的一個副本;(3)vector<T> v3(n,i);v3包含n個值爲i(得是T類型)的元素。(4)vector<T> v4(n);v4含有值初始化的元素的n個副本。

    vector對象可以在運行時高效地添加元素。(而對於java早期的Vector類的所有方法是同步式的方法,因此對於無需同步操作時,要浪費很多時間。C++的vector不是同步的)。

    如果沒有指定元素的初始化式,那麼標準庫將自行提供一個元素初始值進行值初始化

3.3.2、vector對象的操作

    vector對象的size類似於string類型,size返回相應vector類定義的size_type的值,vector類型總是包含vector的元素類型:如,vector<int>::size_type

    push_back()操作(之前一直納悶爲啥這麼命名):也就是“插入(push)”到vector對象的“後面(back)”。

    vector的下標操作,vector元素的位置從0開始。如for循環:for(vector<int>::size_type ix = 0;ix !=ivec.size(); ++ix){ivec[ix] = 0;}

    關於上述“!=”習慣是合理的(需要學習泛型編程才能體會)。

    沒有事先記錄size返回值而是直接在for循環中調用size()方法反映一種良好的編程習慣。因爲循環中很可能導致vector元素的增減,直接調用size()就不怕vector長的變量過期了。

    下標操作不添加元素(如對空vector<int> vc執行vc[0]=1是錯誤的不會添加元素,得用push_back()方法),必須是已存在的元素才能用下標操作符進行索引。通過下標操作進行賦值時,不會添加任何元素。試圖對不存在的元素進行下標操作是程序設計過程中常犯的嚴重錯誤。所謂的“緩衝區溢出”錯誤就是對不存在的元素進行下標操作的結果。(與下面摘抄的無衝突,看似是內存訪問越界,其實還帶有“覆蓋”在裏面)

    網上摘抄:內存溢出就是你要求分配的內存超出了系統能給你的,系統不能滿足

需求,於是產生溢出(如new之後忘記delete)。內存訪問越界,簡單的說,你向系統申請了一塊內存,在使用這塊內存的時候,超出了你申請的範圍。緩衝區溢出是指當計算機向緩衝區內填充數據位數時超過了緩衝區本身的容量,溢出的數據覆蓋在合法數據上。棧溢出就是緩衝區溢出的一種。

3.4、迭代器簡介

    vector<int>::iterator iter;(尖括號中int是看vector存的元素決定)每種容器都定義了一對命名爲begin和end函數用於返回迭代器。由end操作返回的迭代器指向vector的“末端元素的下一個”。通常稱爲超出末端迭代器(off-the-enditerator)。表明它指向一個不存在的元素,只是起了哨兵的作用。如果vector爲空,begin返回的迭代器與end返回的迭代器相同。迭代器可以用解引用操作符(*操作符)來訪問迭代器所指向的元素,如*iter。(注:由於end操作返回的迭代器不指向任何元素,因此不能對它進行解引用或自增操作)。迭代器操作樣例:

for(vector<int>::iterator iter = ivec.begin();iter!= ivec.end();++iter)*iter=0;

    const_iterator(如,vector<string>::const_iterator iter),在解引用時可以得到一個指向const對象的引用,這樣藉助*想修改所指向的內容則不允許。即我們得到一個迭代器,它自身的值可以改變,但不能用來改變其所指向的元素值。注:常量迭代器(如,constvector<int>::iterator iter),聲明一個const迭代器時,必須初始化迭代器,一旦被初始化後,就不能改變它的值(即本身的值,但該常量迭代器指向的值可以改變)。還有如constvector<int> nines(10,9);則不可以改變vector中的元素值。(附加:對於java的final變量是不可改變的,但它的值可以在運行時刻初始化,也可以在編譯時刻初始化,甚至可以放在構造函數中初始化,而不必在聲明的時候初始化)。

    迭代器的算術操作:iter1-iter2用來計算兩個迭代器對象的距離,該距離是名爲difference_typesigned類型的值(因爲可能爲負),該類型可以保證足夠大以存儲任何兩個迭代器對象間的距離。iter1和iter2兩者必須都指向同一vector中的元素或者指向vector末端之後的下一個元素(迭代器加法也一樣,結果指向元素或者末尾的下一個元素)。(任何改變vector長度的操作都會使已存在的迭代器失效,例如在push_back後,就不能再信賴指向vector的迭代器值了)。

    不能用(ivec.begin()+ivec.end())/2求中間值。end指向的是最後一個元素的下一個,對於VS編譯器,上述的+沒有定義,編譯時就錯了。

3.5、標準庫bitset類型

#include<bitset> usingstd:bitset;

3.5.1、bitset對象的定義和初始化

    如bitset<17>bitvec;尖括號中的長度值定義爲整型字面值常量或是已用常量值初始化的整型的const對象(即在編譯時就得知道長度)。

    初始化bitset對象的方法:(1)bitset<n>b;b有n位,每位都是0;(2)bitset<n> b(u);b是unsigned longu的一個副本;(3)bitset<n>b(s);b是string對象s中含有的位串的副本;(4)bitset<n> b(s,pos,n);b是s(s只能是string不能是unsigned long型)中從位置pos開始的n個位的副本。

    用unsigned值初始化bitset對象:該unsigned long型將轉化爲二進制的位模式。長度不夠則高階位被丟棄,否則高階位補0。

    string對象初始化bitset對象:從string對象讀入位集的順序是從右向左。即string對象的最右邊字符用來初始化bitset對象的低階位(即下標爲0的位)。可以想成是直接將string搬過來(即如1100->1100bitset)一樣。(而unsigned則是1100->0011bitset)。

3.5.2、bitset對象上的操作

    count()操作返回置爲1的二進制位的個數:size_t bits_set = bitvec.count();size_t(vector中是size_type)類型定義在cstddef頭文件中,該文件是C標準庫的頭文件stddef.h的C++版本。它是一個與機器相關的unsigned類型,其大小足以保證存儲內存中對象的大小。其size()返回的類型也是size_t。

    訪問bit對象中的位:可以用下標操作符來讀或寫某個索引位置的二進制位。如測試某個二進制位是否爲1,bitvec.test(i)等價於bitvec[i]。對個別位取反bitvec.flip(i)等價於bitvec[i].flip();bitvec.flip()爲對所有位取反。

    獲取bitset對象的值:to_ulong操作返回一個unsigned long值,該值與bitset對象的位模式存儲值相同。僅當bitset類型的長度小於或等於unsigned long的長度時,纔可以使用to_ulong操作(超出,運行時會出錯,unsigned int/long 0~4294967295;long long的最大值:9223372036854775807)。bitset用到了位操作符。
發佈了70 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章