3.4迭代器
和指標不一樣的是,獲取迭代器不是使用取位址符,有迭代器的型別同時返回擁有返回迭代器的成員,比如這些型別都擁有名為begin和end的成員,其中begin成員負責指向第乙個元素的迭代器
auto b=v.begin(),e=v.end();//b和e的型別相同
end成員則負責返回指向容器(或string物件)「尾元素的下乙個位置」的迭代器,也就是說,該迭代器指示的是容器的乙個本不存在的「尾後」元素,這樣的迭代器沒什麼意義,僅僅是個標記而已。end成員返回的迭代器常被稱作尾後迭代器
迭代器運算子
使用==和!=來比較兩個合法的迭代器是否相等,如果兩個迭代器指向的元素相同或者都是同乙個容器的尾後迭代器,則它們相等;否則就說這兩個迭代器不相等。
見表p96頁
*iter//返回迭代器iter所指元素的引用
iter->men//等價於(*iter).mem
++iter//
--iter//令iter指向容器的上乙個元素
iter1==iter2判斷兩個迭代器是否相等(不相等)如果兩個迭代器指向的是同乙個元素或者它們是同乙個容器的尾後迭代器,則相等反之不相等
string s(「some string」);
if(s.begin()!=s.end())
將迭代器從乙個元素移動到另外乙個元素
迭代器型別
一般來說我們也不知道迭代器的精確型別。而實際上,那些擁有迭代器的標準庫型別使用iterator和const——iterator來表示迭代器的型別:
vector::iterator it//it能讀寫vector的元素
string::iterator it2;//it2能讀寫string物件中的字元
vector::const_iterator it3;//it3只能讀元素不能寫元素
string::const_iterator it4;//it4只能讀字元,不能寫字元
const_iterator和常量指標差不多,能讀取但不能修改它所指的元素值,相反,iterato的物件可讀可寫。如果vector 物件或string物件是乙個常量,只能使用const——iterator;如果vector物件或string物件不是常量,那麼既可以使用iterator也能使用const——iterator
begin 和end 運算子
begin和end返回的具體型別由物件的是否是常量決定,如果物件是常量,begin和end返回const_iterator;
如果物件不是常量,返回iterator:
vector v;
const vectorcv;
auto it1=v.begin();//it1型別是vector::iterator
auto it2=cv.begin();//it2的型別是vector::const_iterator
如果物件只需讀操作而非寫操作最好使用常量型別。為了便於得到const_iterator型別的返回值,c++11引入了兩個新函式,分別是cbegin和cend:
auto it3=v.cbegin();//it3的型別是vector::const_iterator
類似於begin和end
不論vector物件本身是否是常量返回值都是const_iterator。
結合解引用和成員訪問操作
解引用迭代器可獲得迭代器所指的物件,例如,對於乙個字串組成的vector物件來說,要想檢查其元素是否為空,令it是該vector物件的迭代器,只需檢查it所指字串是否為空,令it是該vector物件的迭代器,只需檢查it所指字串是否為空
(*it).empty()
(*it).empty()中的園括號必不可少,該表示式的含義是先對it解引用,然後解引用的結果再執行點運算子,如果不加圓括號,點運算子由it執行,而非it解引用的結果:
(*it).empty()//解引用it,然後呼叫結果物件的empty()
*it.empty()//錯誤試圖it的名為empty的成員,但it是個迭代器沒有empty成員
為了簡化上述表示式c++語言定義了箭頭運算子(->)箭頭運算子把解引用和成員訪問兩個操作結合在一起
p99-p101見課本
3.5陣列是一種復合型別陣列宣告形如a[d],a是陣列名字,d是陣列維度,維度必須大於0,陣列的維度必須是乙個常量表示式
unsigned cnt=42;//不是常量表示式
constexper unsigned sz=42;//常量表示式關於constexper
int arr[10];//含有10個陣列
int *parr[sz];//含有42個整型指標的陣列
string bad[cnt]//錯誤,cnt不是常量表示式
string strs[get_size()]//get_size()是constexpr時正確;否則錯誤
定義陣列的時候必須制定陣列的型別,不允許使用auto關鍵字來初始值的列表推斷型別。另外和vector一樣,陣列的元素應為物件,因此不存在引用的陣列
顯示初始化陣列
可以對陣列的元素進行初始化列表,此時允許忽略陣列維數,指明了維數,初始化的總數量就不應該超出指定大小,如果超出就會預設值
const unsigned sz=3;
int ia1[sz]=;
int a2=;
int a3[5]=;
string a4[3]=;//等價於a4=
int a5[2]=;//錯誤初始值過多
理解複雜的的陣列宣告
和vector一樣,陣列能存放大多數型別的物件,可以定義乙個存放指標的陣列。又因為陣列本身是物件,所以允許定義陣列的指標和陣列的引用
int
*ptrs[10];
int &refs[10]=/*?*/
int (*parray)[10]=&arr;
int(&arrref)[10]=arr;
預設情況下,型別修飾符從右往左依次繫結。對於ptrs來說從右往左理解其含義比較簡單:首先我們定義乙個大小為10的陣列,它的名字是ptrs,然後知道陣列中存放的是指向int的指標但是對於parray來說,從右往左理解就是不合理了因為陣列的維度緊跟著被宣告的名字,所以就陣列而言從內往外閱讀比較好來理解parray:首先是圓括號的部分*parray意味著parray是個指標,接下來觀察右邊,可知道parray是個指向大小為10的陣列的指標,最後觀察左邊知道陣列中的元素是int。這樣最終含義就明白無誤了,parray是乙個指標,它指向乙個int陣列,陣列包含10個元素。同理(&arrref)表示arrref是乙個引用,它引用的物件的大小為10的陣列,,陣列元素的型別是int當然,對修飾符的數量並沒有特殊限制:
int*(&arry)[10]=ptrs;
按照由內往外閱讀上述語句,首先知道array是乙個引用,然後觀察右邊知道arry引用的物件是乙個大小為10的陣列,最後觀察左邊知道,陣列的元素型別是指向int的指標。這樣arry就是乙個含有10個int型指標的陣列的引用。
從內往外的順序讀
訪問陣列元素
陣列除了大小固定這一特點外,其他用法與vector型別相似,例如可以用陣列記錄個分數段的成績個數,從而實現與程式一樣的功能
unsigned scored[11]={};
unsigned grade;
while(cin>>grade)
最好使用下面的語句
for(auto i:scores)
cout<
for(int *b=arr;b!=e;++b)
cout<<*bc++11引入兩個名為begin和end功能與之前的相似,不過陣列不是類型別,因此這兩個函式不是成員函式,正確的形式是將陣列作為它們的引數
int ia=
int *beg=begin(ia);//指向ia首元素的指標
int *last=end(ia);//指向arr尾元素的下乙個位置的指標
使用begin和end可以很容易地寫出乙個迴圈並處理陣列中的元素。例如,假設arr是乙個整型陣列,下面的程式負責找到arr中的第乙個負數:
int *pbeg=begin(arr),*pend=end(arr);
while(pbeg!=pend&&*pbeg>=0)
++pbeg;
尾後指標不能執行解引用和遞增操作 C primer 讀書筆記
第2 章 變數和基本型別 1 變數直接初始化和變數 複製初始化 int ival 1024 direct initialization int ival 1024 copy initialization 初始化不是賦值 2 內建型別復 制初始化和直接初始化幾乎沒有區別 但 對類型別物件來 說,有些初...
C Primer讀書筆記
前些日子開始看 c primer 順便做一些筆記,既有書上的,也有自己理解的。因為剛學c 不久,筆下難免有謬誤之處,行文更是凌亂 所幸不是用來顯配的東西,發在linuxsir只是為了方便自己閱讀記憶,以防只顧上網忘了正事。書看了不到一半,所以大約才寫了一半,慢慢補充。const要注意的問題 1 下面...
C Primer讀書筆記
前些日子開始看 c primer 順便做一些筆記,既有書上的,也有自己理解的。因為剛學c 不久,筆下難免有謬誤之處,行文更是凌亂 所幸不是用來顯配的東西,發在linuxsir只是為了方便自己閱讀記憶,以防只顧上網忘了正事。書看了不到一半,所以大約才寫了一半,慢慢補充。const要注意的問題 1 下面...