正文之前
其實(shí)我的《C++ Primer》 已經(jīng)看到第五章了,但是因?yàn)榇a字比較費(fèi)時(shí)間,所以暫時(shí)沒(méi)有迅速更新實(shí)在是對(duì)不住,但是沒(méi)辦法, 總不能一天拿出五六個(gè)小時(shí)來(lái)碼字吧。最多三個(gè)小時(shí)不能多了。不過(guò)我后期會(huì)把碼字當(dāng)做是一種復(fù)習(xí)和筆記行為逐步跟上的。至少保證在我這兒可以完整的把《C++ Primer》從頭到尾擼一遍。

正文
1、 數(shù)組的定義和初始化
數(shù)組是一種類似于標(biāo)準(zhǔn)庫(kù)類型vector的數(shù)據(jù)結(jié)構(gòu),但是在性能與靈活性的權(quán)衡上又與vector不同,最大的不同是:數(shù)組的長(zhǎng)度直接顯式的或者間接地被規(guī)定了,是不變的。不能隨意向數(shù)組中添加元素。因?yàn)檫@個(gè)特性,所以某些時(shí)候數(shù)組的性能較好,但是缺乏靈活性。
- 數(shù)組的長(zhǎng)度必須是給定的常量表達(dá)式,書(shū)上是這么說(shuō)的,按照書(shū)上的說(shuō)法下面應(yīng)該報(bào)錯(cuò),但是我的gcc給我的回復(fù)是沒(méi)有錯(cuò)誤。不過(guò)大家還是盡量按照《C++ Primer》的要求來(lái)。
int len=10;
int array[len]
- 數(shù)組的初始化方式:
const unsigned sz=4;
int ial[sz]={1,2,4}; {1,2,4,0}
int a2[]={1,24,3}; // {1,24,3}
itn a3[5]={0,1,2}; //{0,1,2,0,0}
string a3[3]={"abc","def"}; // 三個(gè)字符串 “abc”,“def”,“”
int a5[2]={1,2,3}; //錯(cuò)誤:初始值是三個(gè),但是容量為2;
- 特殊的字符數(shù)組
其特殊之處在于可以用字符串字面值,來(lái)給字符數(shù)組賦值,但是一定要記住,賦值之后,會(huì)默認(rèn)的多出一個(gè)\0結(jié)束符號(hào),這個(gè)符號(hào)會(huì)被放到初始化的內(nèi)容的最后一位,也就是說(shuō)如果你輸入了6個(gè)字符,那么編譯器會(huì)默認(rèn)在第七位加上\0符號(hào)作為arr[6]
char a1[]={'c','b','a'}; // {'c','b','a'}
char a2="c++"; //{'c','+','+','\0'}
char a3[4]="abcd"; //Error:會(huì)自動(dòng)多出來(lái)一個(gè)\0 無(wú)處存放!
- 不允許拷貝和復(fù)制。不能把數(shù)組的內(nèi)容直接拷貝給其他的數(shù)組作為初始值。也不能直接用數(shù)組給其他的數(shù)組賦值。PS:當(dāng)然,有一些編譯器是支持這種行為的,但是這是非標(biāo)準(zhǔn)特性,是編譯器的個(gè)人行為,并非通用!
2、 很經(jīng)典的復(fù)雜的數(shù)組聲明
int *ptrs[10];
從右向左依次綁定。那么ptrs先綁定[10],組成了一個(gè)數(shù)組,然后*代表這個(gè)數(shù)組的元素都是 int * 類型的。所以這個(gè)是代表著10個(gè)int 指針?biāo)M成的數(shù)組的聲明。
char a[10]="IloveYYW";
char &arr[9]='f';
char &d=a;
char &d[10]=a;
char &c=a[7];
cout<<c<<endl;
上面是關(guān)于對(duì)于數(shù)組的引用。實(shí)際運(yùn)行顯示,第二行第三行第四行都是錯(cuò)誤的!?。?!不存在引用的數(shù)組,除非直接引用數(shù)組中的某一個(gè)元素,比如第五行的做法。這就是正確的??!
int (*parr)[10]=&ptrs;
int (&carr)[10]=ptrs;
上面兩句分別是指針和引用兩種常見(jiàn)的類型。為何要放在一起呢?首先容我為你解釋兩句話編譯后的含義:parr是代表著一個(gè)指向容量為10的名為ptrs的數(shù)組的指針。記住,只是一個(gè)指針,不是一個(gè)指針數(shù)組。這個(gè)時(shí)候的[10]只是告訴你,這個(gè)指針指向的是以初始化的值的地址開(kāi)始的長(zhǎng)度為0的空間內(nèi)的數(shù)組,它是指向整個(gè)數(shù)組而不是數(shù)組的首地址,也就是數(shù)組名ptrs所指的地址。ok既然知道了這個(gè)[10]的含義,那么我們就知道了下面的引用的含義了。另外注意,()是必不可少,不然由于優(yōu)先級(jí)的問(wèn)題,會(huì)造成很嚴(yán)重的后果。下面是我的一些示例代碼,應(yīng)該有助于各位理解:
char a[10]="IloveYYW";
char &c=a[7];
cout<<c<<endl;
char (*p)[10]=&a;
cout<<(*p)[3]<<endl;
cout<<(*p)<<endl;
p++;
cout<<(*p)<<endl;
char *x=a;
x++;
cout<<*x<<endl;

3、 小小實(shí)戰(zhàn):成績(jī)歸檔
需求:把各個(gè)學(xué)生的成績(jī)錄入后按照十分為一個(gè)層次歸檔。最后輸出各個(gè)層次的成績(jī);
分析:用一個(gè)含有11個(gè)元素的數(shù)組來(lái)記錄。每錄入一個(gè)成績(jī),就把對(duì)應(yīng)檔次的數(shù)組元素+1,最后遍歷即可;
實(shí)現(xiàn):
int tar[11];
unsigned int grade;
while(cin>>grade)
{
if(grade<=100&&grade>=0)
++tar[grade/10];
}
for(int i=0;i<=10;i++)
{
cout<<i*10<<"~"<<(i+1)*10<<"分?jǐn)?shù)段有"<<tar[i]<<"人 "<<endl;
}
PS:很重要的一點(diǎn),千萬(wàn)要注意數(shù)組下標(biāo)的合法性。如果出現(xiàn)溢出,那是很麻煩的一件事,所以最好是加上一點(diǎn)合法性測(cè)試,比如上面代碼中的if(grade<=100&&grade>=0)
4、 指針與數(shù)組
數(shù)組有一個(gè)很神奇的也是對(duì)新人十分不友好的特性,那就是數(shù)組名是指向數(shù)組首地址的指針。
string name[3]={"zhang ","zhao","bo"};
string *p=name;
string xp=&name[0]
上面的兩個(gè)指針定義是等價(jià)的,也就是說(shuō)其實(shí)數(shù)組名就等價(jià)于是第一個(gè)元素的地址,你直接用數(shù)組名給一個(gè)指針賦值,送上去的也就是第一個(gè)元素的地址,指針也只指向第一個(gè)元素,而不是整個(gè)數(shù)組所在的塊。上面說(shuō)過(guò)了,要指向塊,必須早數(shù)組的后面跟上數(shù)組的長(zhǎng)度大小。
char a[10]="IloveYYW";
char (*p)[10]=&a;
cout<<(*p)[3]<<endl;
cout<<(*p)<<endl;
p++;
cout<<(*p)<<endl;
char *x=a;
x++;
cout<<*x<<endl;
char *X=&a[0];
X++;
cout<<*X<<endl;

5、 數(shù)組的迭代器(稍微區(qū)別于vector的迭代器)
數(shù)組的迭代器。頭指針好說(shuō),尾后迭代器這個(gè)就不好說(shuō)了。按照尾后迭代器的概念,那么就有如下:
int arr[10];
int *end=&arr[10];
可以看出來(lái),arr[10]是一個(gè)不存在的元素,也是最后一個(gè)元素的下一個(gè)地址。(記?。何埠蟮鞑荒軋?zhí)行解引用以及遞增操作,意思是可以遞減!回到最后一個(gè)元素的地址)完美符合尾后迭代器的概念。但是標(biāo)準(zhǔn)函數(shù)庫(kù)里面其實(shí)已經(jīng)為我們做好了準(zhǔn)備,按照原理來(lái)說(shuō)其實(shí)就是頭指針是數(shù)組名,尾指針是上面的尾后迭代器的概念:
int a[10]={1,2,3,4,5,6,7,8,9,0};
int *beg=begin(a);
int *last=end(a);
再回頭看一下vector的迭代器的操作:
vector<int > v;
auto b=v.begin();
聰明的你一定發(fā)現(xiàn)了~~ 對(duì)于數(shù)組是調(diào)用標(biāo)準(zhǔn)函數(shù)庫(kù)得到的,而對(duì)于vector ,人家是標(biāo)準(zhǔn)庫(kù)類型內(nèi)置函數(shù),雖然效果一樣,但是這個(gè)逼格瞬間就見(jiàn)高低,當(dāng)然,因此數(shù)組的性能要略高于vector是肯定的。但是你耐不住現(xiàn)在的計(jì)算機(jī)計(jì)算能力大大提高,不在乎那么點(diǎn)性能和容量的損失哇?。?/p>
6、 數(shù)組的指針操作
其實(shí)數(shù)組的指針操作基本就是++ -- 那些常見(jiàn)的玩意 一個(gè)數(shù)組的指針加上一個(gè)長(zhǎng)度就是到了距離這個(gè)指針?biāo)傅刂范噙h(yuǎn)距離的地址,這很容易理解對(duì)不,畢竟指針本身是個(gè)對(duì)象,這個(gè)對(duì)象的內(nèi)容是一個(gè)地址,那么好比說(shuō)有一個(gè)游標(biāo),指向一棟大樓的樓層,現(xiàn)在這個(gè)指針指向3樓,你給這個(gè)指針+5 自然就指向8樓了。如果取出對(duì)象內(nèi)的內(nèi)容,就相當(dāng)于是進(jìn)入了八樓的房間咯,這些常規(guī)的就不多說(shuō)了。下面看一個(gè)有意思的。
int a[10]={0,1,2,3,4,5,6,7,8,9};
int *p=&a[4];
cout<<*p<<endl;
cout<<*(p+2)<<" "<<*(p-2)<<endl;
int j=p[2];
int k=p[-2];
cout<<j<<" "<<k<<endl;
想不到還有這種騷操作吧。不過(guò)這種也只能對(duì)著指向數(shù)組某個(gè)元素的指針用。具體的思維是參照坐標(biāo)系中的相對(duì)坐標(biāo)。當(dāng)你重新定向坐標(biāo)原點(diǎn)(首地址,也就是代碼中的p),其實(shí)就相當(dāng)于在平行的平面內(nèi)重定一個(gè)坐標(biāo)系。進(jìn)行相對(duì)的偏移,雖然長(zhǎng)度不變,但是范圍卻變了。好比上面的,數(shù)組的范圍從0~9 變成了 -4~5; 你難道不覺(jué)得p這個(gè)對(duì)象跟a這個(gè)對(duì)象是一個(gè)德行嗎?本身是指針,但是只要又可以加后綴,區(qū)別只是a加后綴默認(rèn)取出元素,p加后綴卻是只表示了偏移量而沒(méi)有取數(shù)操作而已?。?Sexy Operation 吧?。?/p>

7、使用數(shù)組初始化vector對(duì)象(書(shū)中還有些老掉牙的C字符串風(fēng)格與string的操作,但是我覺(jué)得沒(méi)啥用,就不寫(xiě)了)
int arr[3]={1,2,3};
vector<int > ivec(begin(arr),end(arr));
與前面介紹的vector的初始化都不一樣,這次是兩個(gè)迭代器來(lái)初始化。很是神奇,而且得益于指針。我們可以用vector截取數(shù)組的一部分,也就說(shuō)用指針的某一段的頭指針和尾后指針來(lái)初始化一個(gè)vector對(duì)象。當(dāng)然,現(xiàn)代C++應(yīng)該盡量使用vector以及內(nèi)置函數(shù)和迭代器來(lái)避免數(shù)組和指針的使用。避免使用基于C風(fēng)格的字符串。
8 、 多維數(shù)組的初始化
嚴(yán)格來(lái)說(shuō),C++沒(méi)有多維數(shù)組,所謂的多維數(shù)組,其實(shí)是由數(shù)組的元素是數(shù)組這種形式變化而來(lái)。

⑴ 分行進(jìn)行初始化
int a[2][3]={{1,2,3},{4,5,6}};
在{ }內(nèi)部再用{ }把各行分開(kāi),第一對(duì){ }中的初值1,2,3是0行的3個(gè)元素的初值。第二對(duì){ }中的初值4,5,6是1行的3個(gè)元素的初值。相當(dāng)于執(zhí)行如下語(yǔ)句:
int a[2][3];
a[0][0]=1;
a[0][1]=2;
a[0][2]=3;
a[1][0]=4;
a[1][1]=5;
a[1][2]=6;
注意,初始化的數(shù)據(jù)個(gè)數(shù)不能超過(guò)數(shù)組元素的個(gè)數(shù),否則出錯(cuò)。
⑵ 不分行的初始化
int a[2][3]={ 1,2,3,4,5,6};
把{ }中的數(shù)據(jù)依次賦給a數(shù)組各元素(按行賦值)。即
a[0][0]=1;
a[0][1]=2;
a[0][2]=3;
a[1][0]=4;
a[1][1]=5;
a[1][2]=6;
⑶ 為部分?jǐn)?shù)組元素初始化
int a[2][3]={{1,2},{4}};
第一行只有2個(gè)初值,按順序分別賦給a[0][0]和a[0][1];第二行的初值4賦給a[1][0],其它數(shù)組元素的初值為0。
static int a[2][3]={ 1,2};
只有2個(gè)初值,即a[0][0]=1,a[0][1]=2,其余數(shù)組元素的初值均為0。
⑷ 可以省略第一維的定義,// * * 但不能省略第二維的定義 * *//。
系統(tǒng)根據(jù)初始化的數(shù)據(jù)個(gè)數(shù)和第2維的長(zhǎng)度可以確定第一維的長(zhǎng)度。
int a[ ][3]={ 1,2,3,4,5,6};
a數(shù)組的第一維的定義被省略,初始化數(shù)據(jù)共6個(gè),第二維的長(zhǎng)度為3,即每行3個(gè)數(shù),所以a數(shù)組的第一維是2。例如,int a[ ][3]={ 1,2,3,4};等價(jià)于:int a[2][3]={ 1,2,3,4};若分行初始化,也可以省略第一維的定義。下列的數(shù)組定義中有兩對(duì){ },已經(jīng)表示a數(shù)組有兩行。 static int a[ ][3]={{1,2},{4}};
9、 多維數(shù)組的有意思的玩法
注意注意,前面說(shuō)了:數(shù)組的數(shù)組名就是數(shù)組首地址的指針。那么,多維數(shù)組好比是a[2][3],那么a[0],a[1]也是指針?。?! 有意思吧?。?!所以對(duì)于指針來(lái)說(shuō),可以定義指向外層數(shù)組的指針,也可以定義指向內(nèi)層數(shù)組的指針,
int a[2][3]={0,1,2,3,4,5};
int (*p)[3]=a;
cout<<(*p)[2]<<endl;
p++;
cout<<(*p)[2]<<endl;
可見(jiàn),p所指的是第一層,而不是第一層第一個(gè)。那么p++自然就是移到第二層了。然后再在第二層解引用之后由下標(biāo)取值即可!!

如果再改變一下:
int a[2][2][2]={0,1,2,3,4,5,6,7};
int (*p)[2][2]=a;
cout<<(*p)[1][1]<<endl;
p++;
cout<<(*p)[1][1]<<endl;
int (*x)[2]=a[1];
cout<<(*x)[1]<<endl;
畫(huà)圖畫(huà)錯(cuò)了。。集體增加了1,大家小心理解就好,忽略我的錯(cuò)誤,我下面的解釋基于這個(gè)錯(cuò)誤的圖像進(jìn)行講解

指針a所指的其實(shí)是包含了1234 四個(gè)元素的那個(gè)區(qū)塊,而其內(nèi)不是一個(gè)二維數(shù)組,所以在p指針的ID能夠以后加兩個(gè)長(zhǎng)度元素表示其所指向的對(duì)象是一個(gè)二維數(shù)組,a[1]則表示的是包含了56這兩個(gè)元素的那個(gè)塊,所以重新定義p的時(shí)候在后面要加一個(gè)長(zhǎng)度來(lái)表示所指的是一個(gè)一維數(shù)組。so~~ 完了
這個(gè)時(shí)候有一個(gè)auto的出現(xiàn)簡(jiǎn)直是人間福音。。看下面的代碼就知道了:
for(auto p=a;p!=ia+3;++p)
{
for auto q=*p;q!=*p+4;++q)
cout<<*q<<endl;
cout<<endl;
}
這里一不小心就會(huì)把你坑死,因?yàn)閜=ia,所以其實(shí)此時(shí)p是一個(gè)指向一維數(shù)組的指針,解引用后才是指向一維數(shù)組首地址的指針,再次解開(kāi)引用才是真正意義上的a[0][0]
正文之后
哎??,說(shuō)好的寫(xiě)簡(jiǎn)書(shū)只花三個(gè)小時(shí)內(nèi)的時(shí)間,吃完午飯?jiān)趫D書(shū)館玩了一會(huì),處理了下年級(jí)重修的工作后開(kāi)始寫(xiě),寫(xiě)到現(xiàn)在五點(diǎn)多了。少說(shuō)去了四個(gè)小時(shí)?。?!我這是干了什么??。。。。〔恍校?!我要好好開(kāi)始看書(shū)了??!今日簡(jiǎn)書(shū)封筆??!

明日再戰(zhàn)??!