日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++Primer学习笔记:第3章 字符串、向量和数组

發(fā)布時(shí)間:2023/11/30 c/c++ 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++Primer学习笔记:第3章 字符串、向量和数组 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
  • 可以使用using聲明而無需專門的前綴:using namespace::name;.。位于頭文件的代碼一般來說不應(yīng)該使用using聲明,這是因?yàn)轭^文件的內(nèi)容會拷貝到所有引用他的文件中去,如果頭文件中有某個using聲明,那么每個使用了該頭文件的文件都會有這個聲明。對于某些程序來說,由于不經(jīng)意間包含了一些名字,反而可能產(chǎn)生始料未及的名字沖突。

  • 使用string類型需要添加頭文件#include<string>,并且要對string進(jìn)行聲明:using std::string;

  • string類型的初始化:

    string s1; 默認(rèn)初始化,s1是一個空字符串 string s2 = s1; s2是s1的副本,等價(jià)于s2(s1) string s3 = "hello"; s3是該字符串字面值的副本,等價(jià)于s3("hello"); string s4(10, 'c'); s4的內(nèi)容是10個c

    需要注意的是s3是的內(nèi)容不包括字面值最后的空字符。當(dāng)初始值只有一個的時(shí)候,拷貝初始化(使用=)和直接初始化都可以,但是如果有多個初始值(s4的初始化),就只能夠使用直接初始化的方式。

  • string的操作

    os<<s 將s寫入都輸出流os中,返回os is>>s 從is中讀取字符串賦給s,字符串以空白分隔,返回is getline(is, s) 從is中讀取一行賦給s,返回is s.empty() s為空返回true,否則返回false s.size() 返回s中字符的個數(shù) s[n] 返回s中第n個字符的引用 s1+s2 返回s1和s2連接后的結(jié)果 s1=s2 用s2的副本代替s1中原本的字符 s1==s2 如果s1和s2所包含的字符完全一樣,則返回true s1!=s2 <,<=,>,>= 根據(jù)字典序進(jìn)行比較

    可以使用while(cin>>s)進(jìn)行循環(huán)讀入,getline會讀入換行符,但是不會把換行符保存到string對象中。因?yàn)間etline返回的也是輸入流,因此也可以使用while(getline(cin,s))進(jìn)行循環(huán)讀入

  • size()函數(shù)返回值是string::size_type類型,這是一個無符號整型,因此如果我們直接使用size()的返回值和一個負(fù)數(shù)比較,則幾乎肯定是true,這是因?yàn)樨?fù)數(shù)n會自動轉(zhuǎn)換成一個比較大的無符號整數(shù)。(在C++中int和unsigned int在一起的時(shí)候前者會自動轉(zhuǎn)換為后者)。盡量還是用一個int變量保存返回值或者進(jìn)行強(qiáng)制類型轉(zhuǎn)換。

  • 如果兩個字符串前面都相同,長的那個比短的大

  • 復(fù)合運(yùn)算符+=負(fù)責(zé)把右側(cè)string對象追加到左側(cè)string對象的后面

  • 當(dāng)把string對象和字符(串)字面值混在一條語句中使用時(shí),必須確保每個加法運(yùn)算符+兩側(cè)的運(yùn)算對象至少有一個是string

    string a = "Hello"; string b = a + "world" + "!"; //正確 string c = "Hello" + "world" + a; //錯誤

    字符串字面值與string是不同的類型

  • 應(yīng)該盡可能使用C++版本的C標(biāo)準(zhǔn)庫頭文件(去掉結(jié)尾的.h,在前面加上c表示屬于C標(biāo)準(zhǔn)庫的頭文件),雖然兩者內(nèi)容一樣,但是在名為cname中的頭文件中定義的名字從屬于命名空間std,而.h頭文件則不然。

  • 可以使用庫cctype判斷一個字符的類別

    isalnum(c) 當(dāng)c為字母或數(shù)字為真 isalpha(c) 當(dāng)c為字母為真 iscntrl(c) 當(dāng)c為控制字符為真 isdigit(c) 當(dāng)c為數(shù)字為真 islower(c) 當(dāng)c為小寫字母為真 ispunct(c) 當(dāng)c為標(biāo)點(diǎn)符號為真 isspace(c) 當(dāng)c為空白字符為真 isupper(c) 當(dāng)c為大寫字母為真 tolower(c) 如果c是大寫字母則返回小寫字母,否則原樣輸出 toupper(c) 如果c是小寫字母則返回大寫字母,否則原樣輸出
  • 如果想要改變string對象中字符的值則必須把循環(huán)變量定義成引用類型:

    string s; cin >> s; //將s中每個字母變成大寫 for(auto &c : s) {c = toupper(c); } cout << s << endl;

    從這里也可以看出c每次會重新定義

  • string類型的下標(biāo)是string::size_type類型的,任何一個帶符號類型的值將自動轉(zhuǎn)化為這種無符號類型。注意不要越界,越界的行為是未定義的。

  • 注意邏輯運(yùn)算符&&和||的短路性質(zhì)

  • const string的每一個字符是const char類型的

  • 模板本身不是類或者函數(shù),可以將模板看做編譯器生成類或者函數(shù)編寫的一份說明。編譯器根據(jù)模板創(chuàng)建類或函數(shù)的過程成為實(shí)例化 。當(dāng)使用模板時(shí),需要指出編譯器應(yīng)把類或函數(shù)實(shí)例化成何種類型。

    vector<int> a; vector<vector<string>> file;

    vector能容納絕大多數(shù)類型的對象作為元素,但是因?yàn)橐貌皇菍ο?#xff0c;所以不存在包含引用的vector。
    需要指出的是,在舊版本中多維vector的聲明中最后的>之間必須有空格,否則編譯器會認(rèn)為是右移運(yùn)算符。

  • vector初始化:

    vector<T> v1; v1是一個空的vector,潛在的元素是T類型的,執(zhí)行默認(rèn)初始化 vector<T> v2(v1); v2包含有v1所有元素的副本 vector<T> v2 = v1; 等價(jià)于v2(v1) vector<T> v3(n, val)v3包含了n個重復(fù)元素,每個元素的值都是val vector<T> v4(n) v4包含了n個重復(fù)地執(zhí)行了值初始化的對象 vector<T> v5{a, b, c,...}v5包含了初始值個數(shù)的元素,每個元素被賦予對應(yīng)的初始值 vector<T> v5 = {a, b, c...}等價(jià)于v5{a, b, c,...}
  • C++幾種初始化方式一般來說可以相互等價(jià)地使用,但是也有幾種特殊情況:

    • 使用拷貝初始化(使用=的時(shí)候)只能提供一個初始值
    • 類內(nèi)初始化只能使用拷貝初始化或花括號的形式
    • 如果提供的是初始元素之的列表,則只能把初始值放在花括號里而不能放在圓括號里
  • 可以只提供vector對象容納的元素?cái)?shù)量而略去初始值,此時(shí)庫會創(chuàng)建一個值初始化的元素初值,并把它賦給容器中的所有元素。但是如果元素對象是一個類,而這個類明確要求需要提供初始值,則無法完成初始化工作。

  • 如果使用圓括號來初始化,可以說提供的值是用來構(gòu)造vector對象的;如果使用花括號,可以表述成我們想列表初始化該vector對象。但是如果提供的值不支持列表初始化,編譯器就會嘗試?yán)斫鉃橹苯映跏蓟?#xff08;把{當(dāng)做(來處理),如果仍舊無法進(jìn)行初始化,則報(bào)錯

  • 使用push_back方法向vector的尾部添加元素。C++標(biāo)準(zhǔn)要求vector應(yīng)該能在運(yùn)行時(shí)高效添加元素,因?yàn)関ector對象能夠高效地增長,在定義vector對象設(shè)定其大小沒有什么必要,事實(shí)上這么做性能可能更差,這一點(diǎn)和Java不同。

  • 如果循環(huán)體內(nèi)部包含向vector對象添加元素的語句,則不能使用范圍for循環(huán)(for(auto item:a))

  • 常見的vector操作:

    v.empty() v.size() v.push_back(t) v[n] v1 = v2 用v2中元素的拷貝替換v1中的元素 v1 = {a,b,c...} 用列表中元素的拷貝替換v1中的元素 v1 == v2 v1和v2相等當(dāng)且僅當(dāng)他們的元素?cái)?shù)量相同而且對應(yīng)位置的元素值都相同 <, <=, >, >= 顧名思義,以字典順序進(jìn)行比較
  • size函數(shù)返回size_type類型,需要指定對應(yīng)的模板類型,例如:

    vector<int>::size_type //正確 vector::size_type //錯誤

    使用比較運(yùn)算符需要元素可以相互比較
    vector的下標(biāo)運(yùn)算符可用于訪問已經(jīng)存在的元素,而不能用于添加元素

  • 所有標(biāo)準(zhǔn)庫容器都可以使用迭代器,但是其中只有少數(shù)幾種才同事支持下標(biāo)運(yùn)算符。嚴(yán)格來說,string對象不屬于容器類型,但是string支持很多與容器類型類似的操作。這些類型都擁有名為begin和end的成員,其中begin成員負(fù)責(zé)指向第一個元素的迭代器,end成員負(fù)責(zé)返回指向容器尾元素的下一位置的迭代器(尾后迭代器或尾迭代器)。如果容器為空,begin和end返回同一個迭代器。使用auto進(jìn)行迭代器的定義比較方便。
    常見操作:

    *iter 返回迭代器所指元素的引用 iter->member 相當(dāng)于(*iter).member ++iter 令迭代器指向容器的下一個元素 --iter 令迭代器指向容器的上一個元素 iter1 == iter2 判斷兩個迭代器是否相等 iter1 != iter2

    試圖解引一個尾后迭代器是未定義的行為

    //以此處理s的字符串直到我們?nèi)刻幚硗昊蛴龅娇瞻鬃址?/span> for(auto it = s.begin(); it != s.end() && !isspace(*it); ++it) {*it = toupper(*it); }
  • 在C++中我們更愿意使用迭代器和!=判斷是否到達(dá)尾部。這樣做的原因是所有容器都支持這些操作,而下標(biāo)和<則只有很少的容器定義。

  • 迭代器的類型有兩種:iterator和const_iterator,后者表示不能修改元素值,如果vector或string是const的,則只能使用這種類型。

    string::iterator it1; vector<int>::const_iterator it2;

    如果容器是常量,則begin和end返回的類型是const_iterator類型的迭代器。如果我們使用cbegin和cend則無論容器是否是常量都返回const_iterator類型的迭代器。

    //依次輸出text的每一行直到遇到第一個空白行 for(auto it = text.cbegin(); it != text.cend() && !it->empty(); ++it) {cout << *it << endl;3 }
  • 使用范圍for循環(huán)或者使用迭代器進(jìn)行循環(huán)都不能改變?nèi)萜鲗ο蟮娜萘?#xff0c;否則有可能使得迭代器失效

  • 迭代器運(yùn)算:string和vector的迭代器提供了更多的運(yùn)算符,可以讓迭代器每次跨過多個元素,另外也支持迭代器進(jìn)行關(guān)系運(yùn)算

    //小心越界 iter + n 迭代器向后移動n個元素 iter - n 迭代器向前移動n個元素 iter += n iter -= niter1 - iter2 返回兩個迭代器之間的距離 <, <=, >, >=

    其中迭代器之間的-返回difference_type的帶符號整數(shù)

    int bSearch(const vector<int> &a, int x) { auto begin = a.cbegin();auto end = a.cend();auto mid = begin + (end - begin) / 2;while(mid != end && *mid != x){if(*mid < x)begin = mid + 1;else end = mid;mid = begin + (end - begin) / 2;}if(mid == end) return -1;else return mid - begin; }
  • 數(shù)組也是存放類型相同的對象的容器,這些對象本身沒有名字,需要通過其所在位置訪問,不過數(shù)組的大小不能改變。

  • 數(shù)組是一種復(fù)合類型,元素的個數(shù)也屬于數(shù)組類型的一部分,編譯的時(shí)候維度應(yīng)該是已知的(維度必須是一個常量表達(dá)式)。數(shù)組的元素會被默認(rèn)初始化,如果數(shù)組的元素是內(nèi)置類型而且數(shù)組在函數(shù)內(nèi)部定義,則每個元素不會被初始化。不允許用auto關(guān)鍵字由初始值的列表推斷類型,且不存在引用的數(shù)組

  • 如果用初始值列表初始化數(shù)組,則數(shù)組的維度可以不指明,默認(rèn)為初始值列表的長度。如果指定維度的話則維度至少要比初始值列表的長度長,剩下的元素會被默認(rèn)初始化

  • 字符數(shù)組可以用字符串字面值進(jìn)行初始化,不過需要注意的是字符串字面值的末尾有一個空字符也會被拷貝到字符數(shù)組中,因此字符數(shù)組的長度應(yīng)該是可見的字符個數(shù)加一

  • 不能將數(shù)組的內(nèi)容拷貝給其他數(shù)組作為初始值,也不能用數(shù)組為其他數(shù)組賦值

  • 對于聲明中有括號的應(yīng)該先理解括號里面的,再從右往左進(jìn)行理解

    int *ptr[10]; ptr是含有10個整型指針的數(shù)組 int &ptr[10]; 錯誤,不存在引用的數(shù)組 int (*ptr)[10]; ptr是指針,指向含有10個元素的數(shù)組 int (&ptr)[10] = arr; ptr是引用,指向一個含有10個元素的數(shù)組
  • 在使用數(shù)組下標(biāo)時(shí),通常將其定義為size_t了類型。size_t是一種機(jī)器相關(guān)的無符號類型,被設(shè)計(jì)得足夠大能夠表示內(nèi)存中任意對象的大小。在cstddef頭文件中定義

  • 對于數(shù)組我們同樣可以使用范圍for循環(huán):

    unsigned scores[11] = {}; //進(jìn)行初始化 for (auto i : scores)cout << i << " ";
  • 在C++中,使用指針的時(shí)候編譯器一般會把它轉(zhuǎn)換成指針。在很多用到指針名字的地方,編譯器都會自動將其替換為一個指向數(shù)組首元素的指針。

  • 當(dāng)我們將數(shù)組作為一個auto變量的初始值時(shí),推斷得到的類型是指針而非數(shù)組。但是用decltype返回的類型仍然是數(shù)組

    int ia[] = {0, 1, 2, 3, 4}; auto ia2(ia); //ia2是一個整型指針 decltype(ia) ia3 = {}; //含有5個元素的整型數(shù)組
  • 我們可以像使用迭代器一樣使用指針,為了讓指針的使用更簡單、安全,C++11新標(biāo)準(zhǔn)引入兩個名為begin和end的函數(shù)。這兩個函數(shù)定義在iterator頭文件中

    int a[10] = {}; int *beg = begin(a); //相當(dāng)于int *beg = a; int *last = end(a); //相當(dāng)于int *last = &a[10];

    同尾后迭代器一樣,尾后指針不能執(zhí)行解引操作和遞增操作

  • 迭代器支持的操作指針都支持,包括和整數(shù)進(jìn)行加減、指針和指針的減法、指針和指針比較大小,但是需要注意的是上面的操作兩個指針要在同一個數(shù)組中才有意義。特別地,允許給空指針加上或減去一個值為0 的整型常量表達(dá)式。兩個空指針也循序彼此相減,結(jié)果當(dāng)然是0。

  • 指針同時(shí)有解引和其他運(yùn)算的時(shí)候最好加上括號標(biāo)明運(yùn)算順序

  • 標(biāo)準(zhǔn)庫類型限定使用的下標(biāo)必須是無符號類型,而內(nèi)置的下表運(yùn)算無此要求

  • 盡管C++支持C風(fēng)格字符串,但在C++程序中最好還是不要使用他們,這是因?yàn)镃風(fēng)格字符串不僅使用起來不太方便,而且極容易引發(fā)程序漏洞,是諸多安全問題的根本原因。

  • C風(fēng)格字符串存放在字符數(shù)組中并以空字符結(jié)束。

  • 在頭文件cstring中有一些操作C風(fēng)格字符串的函數(shù):

    strlen(p) 返回p的長度 strcmp(p1, p2) 比較p1和p2,如果p1==p2,返回0,如果p1<p2,返回負(fù)數(shù),否則返回正數(shù) strcat(p1, p2) 將p2附加到p1之后,返回p1 strcpy(p1, p2) 將p2拷貝給p1,返回p1

    傳入此類函數(shù)的指針必須指向以空字符作為結(jié)束的數(shù)組

  • 任何出現(xiàn)字符串字面值的地方都可以用以空字符結(jié)束的字符數(shù)組來替代:

    • 允許使用以空字符結(jié)束的字符數(shù)組來初始化string對象或?yàn)閟tring對象賦值
    • 在string對象的加法運(yùn)算中允許使用以空字符結(jié)束的字符數(shù)組作為其中一個運(yùn)算對象(不能兩個對象都是),在string對象的復(fù)合賦值運(yùn)算中允許使用以空白字符結(jié)尾的字符數(shù)組作為右側(cè)的運(yùn)算對象
  • string對象的成員函數(shù)c_str()返回值是一個C風(fēng)格的字符串,也就是說,函數(shù)的返回值是一個指針, 該指針指向一個以空字符結(jié)束的字符數(shù)組,而這個數(shù)組所存的數(shù)據(jù)恰好與那個string對象一樣。結(jié)果指針的類型是const char*,從而確保我們不會改變字符數(shù)組的內(nèi)容。我們無法保證c_str()函數(shù)返回的數(shù)組一直有效,事實(shí)上,如果后續(xù)的操作改變了s的值就可能讓之前返回的數(shù)組失去作用。如果執(zhí)行完c_str()函數(shù)后程序想一直都能使用其返回的字符數(shù)組,最好將該數(shù)組重新拷貝一份。

    const char *str = s.c_str();
  • 允許使用數(shù)組來初始化vector對象,只需要指明拷貝區(qū)域的首元素地址和尾后地址即可。

    int int_arr[] = {0, 1, 2, 3}; vector<int> a(begin(int_arr), end(int_arr));
  • 現(xiàn)代的C++程序應(yīng)當(dāng)盡量使用vector和迭代器,避免使用內(nèi)置數(shù)組和指針;應(yīng)該盡量使用string,避免使用C風(fēng)格的基于數(shù)組的字符串

  • C++語言中沒有多維數(shù)組,通常所說的多維數(shù)組其實(shí)是數(shù)組的數(shù)組。

  • 多維數(shù)組的初始化

    int ia[3][4] = {{0, 1, 2, 3}.{4, 5, 6, 7},{8, 9, 10, 11} }; int ia[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; int ia[3][4] = { {0}, {4}, {8} }; 只初始化每行的首元素,其他未列出的元素執(zhí)行默認(rèn)初始化 int ia[3][4] = {0, 3, 6, 9}; 只初始化第一行的元素,其他的初始化為0

    多維數(shù)組的操作:

    int (&row)[4] = ia[1]; //把row綁定到ia的第二個4元素?cái)?shù)組上 int cnt = 0; for (auto &row : ia) {for( auto &col : row) {col = cnt++;} }

    注意:要使用范圍for循環(huán)處理多維數(shù)組,除了最內(nèi)層的循環(huán)外,其他所有循環(huán)控制變量都應(yīng)該是引用類型。如果不是引用類型,編譯器的會把數(shù)組類型轉(zhuǎn)化成指針類型,這樣內(nèi)層循環(huán)就無法使用范圍for語句了,因?yàn)閷σ粋€指針進(jìn)行循環(huán)顯然沒有意義。

  • 當(dāng)程序使用多維數(shù)組的名字時(shí),也會自動將其轉(zhuǎn)換成指向數(shù)組首元素的指針。因?yàn)槎嗑S數(shù)組實(shí)際上是數(shù)組的數(shù)組,所以由多維數(shù)組名轉(zhuǎn)換得來的指針實(shí)際上是指向第一個內(nèi)層數(shù)組的指針。

    int ia[3][4] int (*p)[4] = ia; //p指向含有4個整數(shù)的數(shù)組ia[0] p = &ia[2]; //p指向ia的尾元素ia[2]

    上面的括號必不可少,如果沒有括號,int *p[4]的意義將會是大小為4的整型指針數(shù)組

  • 隨著C++11新標(biāo)準(zhǔn)的提出,通過使用auto或者decltype就能盡可能避免在數(shù)組前面加上一個指針類型了。

    int a[3][4]; for (auto p = ia; p != ia + 3; ++p) { //int (*p)[4]for (auto q = *p; q != p + 4; ++q) {//int *qcout << *q << ' ';}cout << endl; }

    可以使用標(biāo)準(zhǔn)庫函數(shù)begin和end實(shí)現(xiàn)同樣的功能:

    for (auto p = begin(ia); p != end(ia); ++p) {for (auto q = begin(*p); q != end(*p); ++q) {cout << *q << ' ';}cout << endl; }

    可以使用類型別名簡化多維數(shù)組的指針

    using int_arr = int[4]; typedef int int_arr[4]; //同上面等價(jià)+
  • 第三章看完啦,啦啦啦啦,后面要稍微加快進(jìn)度

總結(jié)

以上是生活随笔為你收集整理的C++Primer学习笔记:第3章 字符串、向量和数组的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。