【計算機本科補全計劃】《C++ Primer》String Vector標(biāo)準(zhǔn)庫及迭代器的使用

正文之前

今天幫學(xué)妹選了一天的電腦配件,然后從中領(lǐng)悟:坐看狗東黑我錢,任他漲價我不動??!最后果斷的用學(xué)妹的錢沖了個Plus,然后領(lǐng)了一堆券,最后學(xué)妹還省了30塊,另外昨晚找到了一個買酷睿i7 7700k 送主板的,又省了250,然后各種大小活動都去看了個遍,總算是學(xué)會了怎么省錢,特此還要多謝我華科電信的一位大佬--“大王”巍的指點,不然我肯定被狗東坑到懷疑人生。看配置的直接翻到正文之后看!


正文


1、 命名空間using聲明

我們自己平時用的時候是:

using namespace std;

老實說我也就會這一句,所以其他的基本漠不關(guān)心,但是既然書里講了我也就寫出來了。一般的格式如下:

using std::cin;

有了上面這句,以后寫cin就只是cin了。不需要std::cin了。不過也僅限于此,cout還是沒法直接用,不過這樣的好處就是可以單獨的引用,不會造成浪費(Maybe)?

另外頭文件不應(yīng)該包含著using聲明,因為頭文件的內(nèi)容會被拷貝到所有引用他的文件中取去,如果頭文件內(nèi)有這個using聲明,那么每一個使用了該文件的文件就會有這個聲明,對于某些程序來說,由于不經(jīng)意間包含了一些名字,反而可能會產(chǎn)生始料未及的名字沖突。


2、 標(biāo)準(zhǔn)庫 string的基本操作

首先,要使用string這個標(biāo)準(zhǔn)庫就要聲明下頭文件

#include <string>
using std::string
  • string的初始化
    有以下幾種種方式
string s1;    //s1:empty
string s2=s1;    //s2: empty
string s3="string";    //s3:string\0
string s4(10,'c')   //s4:cccccccccc
string s5("string");    //s5:string\0

幾種方式的過程和效果我都寫出來了,就不多贅述了。

  • string對象的上的操作
操作形式 效果
cout<<s 標(biāo)準(zhǔn)輸出流。輸出整個字符串
cin>>s 從cin標(biāo)準(zhǔn)輸入流中一次讀取,直到遇到空白符號停下
getline(cin,s) 從cin標(biāo)準(zhǔn)輸入流中一次讀取一行,不到換行符不停止讀取,可以讀空白
s.empty 判斷是否為空,為空則返回true(bool)
s.size() 直接讀取字符串的字符個數(shù),包括’\0‘
s[n] 直接讀取s這個字符串中第n個字符,從0開始計算
s1+s2 連接兩個字符串
s1=s2 拷貝賦值
s1==s2 判斷兩個字符串是否相等,相等則返回true(bool)
s1!=s2 判斷兩個字符串是否不等,不等則返回true(bool)
<,>,<=,>= 關(guān)系運算符,進行字符串的大小比較,后面說
  • 下面詳細說明各個操作:
    • 讀寫操作,讀取的時候自動忽略開頭的空白,遇到第一個非空字符開始讀取,之后遇到第一個空白字符就停止讀取,不管后面還有沒有,也不讀取空白字符,輸入“ hello world ??!”,最后在cin>>s 中讀取到的只有s=“hello\0”;

    • 讀取操作可以多個對象一起進行:cin>>s1>>s2; 那么“ hello world ??!”最后的結(jié)果是:s1=“hello”;s2=“world”;

    • 使用getline(cin,s)讀取一整行,getline()是無返回值函數(shù),直接對s進行操作,所以不需要額外的空間承載返回值;getline()見到"\0"就結(jié)束輸入,但是得到的字符串不含有換行符,所以如果要按行輸出,那么就要自己手動加上換行操作。

    • empty() ,size()操作都是很顯而易見的,帶有返回值的函數(shù),而且不需要傳入?yún)?shù),是string自帶的一個成員函數(shù),只需要使用點操作符調(diào)用即可:s.empty() s.size() ,前者返回一個bool變量,后者直接返回一個string::type_size的無符號整數(shù)變量,它能夠存放下任何string的大小,是其專屬的大小變量。若要在外部定義string::type_size類型的變量,可以用auto或者是decltype得到。
      auto len=s.size(); decltype(s.size()) len;

    • 比較運算符其實也沒啥差別,但是比較大小的話,string中有一套規(guī)則(但是我自己總結(jié)下來:只要從頭開始看起,第一個不相同的對應(yīng)位置的字符比較大小就全權(quán)代表了這個字符串的大小,另外結(jié)束符號小于一切的字符!通用,不信你看):
      * 如果兩個string長度不同,較短的string對象每個字符都與較長的對象對應(yīng)部分相同,那么較短的就短于長的;(like:abc < abcd )
      * 如果在相應(yīng)的位置不一樣,那么就比較第一個相異的字符;(like: abd > abcd )

    • 相加相減操作:就直接加上咯,相當(dāng)于拼接,反正string是動態(tài)增長長度的,所以隨便你加多少。還有一種騷操作,那就是直接用原本的字符串變量直接加上一個字符串:但是記住,加號兩邊一定要有一個是string變量,兩個字符串字面值直接加起來是違法操作!``` string s2=s1+"zhang"+"z"+"b" //從左到右相加,所以左邊一直都是string變量!!


3、 處理string對象中的字符

字符操作形式 效果(s指string對象中的單個字符)
isalnum(s) 判斷字符是否是字母或數(shù)字;
isalpha(s) 判斷字符是否是字母;
iscntrl(s) 判斷字符是否是控制字符;
isdigit(s) 判斷字符是否是數(shù)字;
isgraph(s) 判斷字符是否是可打印的非空格字符;
ispunct(s) 判斷字符是否是標(biāo)點符號;
isspace(s) 判斷字符是否是空白字符;
isupper(s) 判斷字符是否是大寫字母;
isxdigit(s) 判斷字符是否是十六進制數(shù);
toupper(s) 轉(zhuǎn)換為大寫字母;
tolower(s) 轉(zhuǎn)換為小寫字母。

采用基于范圍的for循環(huán)實現(xiàn):

for ( auto c:str)  //此句的意思是:對于str中的每個字符進行拷貝
  cout<<c<<endl;

上述只能實現(xiàn)讀而不能實現(xiàn)存,因為是直接拷貝,所以無法對string的單個字符進行操作,但是如果是引用,就可以實現(xiàn)了。

for ( auto &c:str)  //此句的意思是:對于str中的每個字符進行引用
{
  cout<<c<<endl;
  c=toupper(c);
}

利用這些特性,結(jié)合一個大家常見的下標(biāo)運算符(這個點就不講了,跟數(shù)組一樣,爛大街了),我自己實現(xiàn)了一個把所有的英文單詞的首字母改成大寫的程序:

string w="hello boy I don't want to hurt you? baby~~~";
w[0]=toupper(w[0]);
for (decltype(w.size()) index=0; index < w.size(); ++index)
{
    if (isspace(w[index]))
    {
        w[index+1]=toupper(w[index+1]);
    }
}
cout<<"================================================\n"<<w<<"\n================================================\n"<<endl;

4、 標(biāo)準(zhǔn)庫類型Vector定義與初始化

  • vector是一種對象的集合,可以看作是一種容易,好比是房子,前面的string可以看做是教室排座位,每個座位上按序號只能坐入字符,不能是別的類型,并且多個字符可以組成一個小組,string對象就是一個小組;而vector就好比是大樓,可以安置的類型更加寬廣。可以放入int,string,char等一些類型。因為在具體定義一個vector對象前不知道類型,所以我們稱之為類模板,對其實施創(chuàng)建的時候稱此過程為實例化,定義如下:
vector<int> ivec;
vector<string> strvec;
vector<vector<int> > vecivec; 

因為vector是容納對象的,所以不存在包含引用的vector;初始化如下:

vector<T> tvec;   // Empty vector
vector<T> tvec(v1);  //  copy v1 to tvec
vector<T> tvec = v1 ; // 同上
vector<T> tvec(n,val); //tvec包含了n個相同T類型的val元素;
vector<T> tvec(n); //執(zhí)行n次空的初始化;
vector<T> tvec{a,b,c,d  ···};  //具體的初始化
vector<T> tvec={a,b,c,d ···};  //同上

注意如果是拷貝初始化的話,不同類型的vector是不能相互拷貝的!


5、 向vector中添加元素

對于vector這個容器,只能用專用的內(nèi)置函數(shù)來對其增加元素,push_back具體用法如下:

vector<int> ivec;
for(int i=0;i!=100;++i)
{
  ivec.push_back(i);
}

從上面我們可以知道,vector具有良好的動態(tài)增長的性能,所以一開始如果就限定其大小的話,是一種對特性的浪費,一開始初始化的時候就限定容量是不是一件明智的事情!(注意,其實上面的操作不是很符合規(guī)定,因為隱性規(guī)定:在循環(huán)體中改變了遍歷序列的長度的操作不用for 循環(huán),可能造成緩沖區(qū)溢出)


6、 其他vector操作

匯總的Vector操作,假設(shè)c是vector變量 效果
c.clear() 移除容器中所有數(shù)據(jù)。
c.empty() 判斷容器是否為空。
c.erase(pos) 刪除pos位置的數(shù)據(jù)
c.erase(beg,end) 刪除[beg,end)區(qū)間的數(shù)據(jù)
c.front() 傳回第一個數(shù)據(jù)。
c.insert(pos,elem) 在pos位置插入一個elem拷貝
c.pop_back() 刪除最后一個數(shù)據(jù)。
c.push_back(elem) 在尾部加入一個數(shù)據(jù)。
c.resize(num) 重新設(shè)置該容器的大小
c.size() 回容器中實際數(shù)據(jù)的個數(shù)。
c.begin() 返回指向容器第一個元素的迭代器
c.end() 返回指向容器最后一個元素的迭代器

我們可以看到,對于vector只有一種添加元素的辦法,但是對于元素的讀寫,可以直接用下標(biāo)表示法,這個數(shù)組,string是完全共同的, 但是請注意,千萬不要給定一個不存在的下標(biāo),如果超出了vector變量的長度,那么毫無疑問你的,會產(chǎn)生嚴(yán)重錯誤!甚至可能導(dǎo)致 緩存區(qū)溢出!!


7、 迭代器

  • 迭代器的介紹
    • 迭代器類似于指針類型,它也提供了對對象的間接訪問。
    • 指針是c語言中就有的東西,迭代器是c++中才有的,指針用起來靈活高效,迭代器功能更豐富些。
    • 迭代器提供一個對容器對象或者string對象的訪問的方法,并且定義了容器范圍。
  • 對于上面介紹的幾種標(biāo)準(zhǔn)庫類型,都有內(nèi)置的迭代器操作,所謂迭代器,就是兩個地址。比如說下面的例子:
vector<int > v;
auto b=v.begin();

此時如果可以查看b的類型,你會發(fā)現(xiàn)其實就是個指針對象。只是其類型由編譯器給定。我們只管auto 或者 decltype就好了!,另外還有一個end()函數(shù)返回尾后迭代器,沒有什么實際意義,正如名字,是在最后一個元素的下一個位置,用于判斷是否為空的容器(begin end指向一個位置的時候)

  • 下面是一些關(guān)于迭代器的操作,其中iter就是迭代器,跟指針其實沒啥區(qū)別


  • 每種容器類型都定義了自己的迭代器類型,如vector

vector<int>::iterator iter;

語句定義了一個名為 iter 的變量,它的數(shù)據(jù)類型是 vector<int > 定義的 iterator 類型。每個標(biāo)準(zhǔn)庫容器類型都定義了一個名為 iterator 的成員,這里的 iterator 與迭代器實際類型的含義相同。

  • 前面的程序用vector::iterator 改變 vector 中的元素值。每種容器類型還定義了一種名為 const_iterator 的類型,該類型只能用于讀取容器內(nèi)元素,但不能改變其值。? 當(dāng)我們對普通 iterator 類型解引用時,得到對某個元素的非 const。而如果我們對const_iterator 類型解引用時,則可以得到一個指向 const 對象的引用,如同任何常量一樣,該對象不能進行重寫。
for (vector<string>::const_iteratoriter = text.begin();iter != text.end(); ++iter)
    cout << *iter << endl; // printeach element in text

? 使用 const_iterator 類型時,我們可以得到一個迭代器,它自身的值可以改變,但不能用來改變其所指向的元素的值??梢詫Φ鬟M行自增以及使用解引用操作符來讀取值,但不能對該元素賦值。

  • 使vector對象的迭代器失效的操作
    • for中添加元素
    • push_back或者改變?nèi)萘康牟僮?/li>

記住一點:但凡是使用了迭代器的循環(huán)體,此時就不要像迭代器所屬的容器進行添加元素的操作了?。?!千萬不要!!

  • 迭代器的算術(shù)操作(跟指針沒差別,只是是標(biāo)準(zhǔn)庫自帶的類型)
iter + n
iter - n
iter1 - iter2
vector<int>::iterator mid = vi.begin() +vi.size() / 2;

任何改變 vector 長度的操作都會使已存在的迭代器失效。例如,在調(diào)用 push_back 之后,就不能再信賴指向 vector 的迭代器的值了!!!!!!!~


正文之后

我只能看著這個配置流口水?。?!具體的購買詳細和指導(dǎo)請看我另一篇文:萬元臺式機組裝養(yǎng)成記


后來又加了三件配個套:


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容