1. 程式人生 > >《c++ primer》第四章--陣列和指標

《c++ primer》第四章--陣列和指標

陣列是c++中類似於標準庫vector型別的內建資料結構,與vector相似,陣列也是一種儲存單一型別物件的容器,其中每個物件沒有單獨的名字,而是通過它在陣列中的位置對它進行訪問。

與vector型別相比,陣列的顯著缺陷在於:陣列的長度是固定的,而且程式設計師無法知道一個指定陣列的長度。陣列沒有獲得其容量大小的size操作,也不提供push_back操作在其中自動新增元素。如果需要更改陣列的長度,程式設計師只能建立一個更大的新陣列,然後把原陣列的所有元素複製到新陣列空間中去。~~~~(>_<)~~~~太費勁了...

在現在c++中,更多的使用vector容器來取代陣列,陣列被嚴格限制與程式內部使用,只有當效能測試表明使用vector無法達到必要的速度要求時,才使用陣列。(看來vector容器雖然用起來很方便,但是速度上不太行啊~~)。

&4.1.1

關於陣列的定義和初始化:

陣列的維數必須用大於等於一的常量表達式定義,此常量表達式只能包含整形字面值常量、列舉常量或者用常量表達式初始化的整型const物件。非const變數以及要到執行階段才知道其值的const變數都不能用於定義陣列的維數。  ————注意,是陣列的維數,不是陣列中某個 元素的值~~

例子:

//  both buf_size and max_files are const

const unsigned buf_size = 512,max_files = 20 ;

int staff_size = 27;  nonconst

const unsigned sz = get_size() ;//const value not known until run time

char input_buffer [ buf _ size ] ;//ok:const variable

string fileTable  [max_size +1 ];// OK:const expression

double salaries [staff_size];//error: non const variable

int test_scores  [ get_size ];//error: non  const expression

int vals [ sz ];//error: size not known until run time

首先,雖然staff_size是用的字面值常量進行初始化,但是staff_size本身是一個——————非const物件,所以只有在執行時才能獲得它的值————————。

因此,使用該變數來定義陣列維數是非法的。而對於sz,儘管它是一個const物件,但是它的值要等到執行時呼叫get_size函式後才知道,因此,它也不能用於定義陣列維數。另一方面,由於 max_files 是const 變數,因此表示式

max_size+1

是常量表達式,編譯時即可計算出該表示式的值為21。

1.

顯示初始化陣列元素:

在定義陣列是,可為其元素提供一組用逗號分隔的初值,這些初值用 { } 括起來,稱為初始化列表:

const unsigned array_size=3;

int ia  [ array _ size ] = { 0 , 1,  2 } ;

ps:

如果沒有顯示提供元素初值,則陣列元素會像普通變數一樣初始化:

※在函式體外定義的內建陣列,其元素均初始化為0;

※在函式體內定義的內建陣列,其元素無初始化;

※不管陣列在哪裡定義,如果其元素為類型別,則自動呼叫該類的預設建構函式進行初始化;如果該類沒有預設建構函式,則必須為該陣列的元素提供顯示初始化。

※※ 除非顯式地提供元素初值,否則內建型別的區域性陣列元素沒有初始化。此時,除了給元素賦值外,其他使用這些元素的操作無意義。 ※※

顯式初始化的陣列不需要提供指定陣列的維數,編譯器會根據列出的元素個數類確定陣列的長度。

EG:

int  a [ ] = { 0 , 1 , 2 } ;

如果初始化列表中維數小於列出的元素個數,那麼會怎麼樣呢?

EG:

int ia  [ 3 ] = { 0 , 1 , 2 , 3 , 4 , };     //error:   當家應該能猜到這個錯誤是什麼。。。初始值設定太多(⊙﹏⊙)b

※ 2

特殊的字元陣列:

字元陣列既可以用一組由花括號括起來、用逗號隔開的字元字面值進行初始化,也可以用一個字串字面值進行初始化。然而,要注意的是兩種初始化方式並不完全是相同,字串字面值包含一個額外的空字元(NULL) 用於結束字串。當使用字串字面值來建立新陣列時,將在新陣列中加入空字元。

char  ca [  ] = { " C++" } ;

ca有四個元素,c,+,+,‘\0’   

※ 注意:

與vector不同的是,一個數組不能用另一個數組進行初始化,也不能將一個數組賦值給另一個數組,這些操作都是違法的~~!違法!

※4.1.2

陣列的操作:

和vector操作一樣,陣列元素可以用下表操作符來訪問,陣列元素也是從0開始計數。

在這裡要注意一點,在c++中,vector使用vector::size_type作為下表型別,而陣列下標的正確型別則是size_t(也就是說,用int)也是可以的)~~~

i例如:

int main()
{
const size_t a_size = 5;
const int a_s = 6;
int ia[a_size];
int iaa[a_s];
}

這兩種方式都是可以的,但是在程式設計序時千萬別忘了int a_s前面的const,如果忘了就去上面看一下。

ps:

在我們使用陣列的時候,千萬要對陣列下標進行檢查,以防 “ 過界 ”,導致安全問題的最常見原因是所謂 “ 緩衝區溢位 ”,就是因為在程式設計時沒有檢查下標,這種錯誤常常會讓人忽略,但確實是不容輕視的一個錯誤。

※4.2

指標的引入:

首先,指標的概念很簡單:用於指向物件。和迭代器一樣,指標提供對其所指物件的間接訪問,只不過是指標結構更通用一些。當然,和迭代器不同的是,指標指向單個物件,而迭代器只能用於訪問容器內的元素。

*****************具體來說,指標儲存另一個物件的地址~

※4.2.2

指標的定義:

c++中使用*符號把一個識別符號宣告為指標:
vector  < int >   *pvec;

int  *p1;

string *ps;

在c++中  也可以使用這種風格宣告指標:
string*     ps;

ps也是指向string物件的一個指標。

PS:

不過在,上面的第二種宣告指標的風格很容易讓人誤解,而且在下面這個語句中:

string*    ps1,ps2;

只有ps1是一個string * 型別,而ps2只是一個普通的string型別的物件~~!

4

指標可能的取值:
一個有效指標必然是一下三種狀態之一:

( 1 ): 儲存一個特定物件的地址;

( 2 ): 指向某個物件後面的另一個物件;

( 3 )   : 0值。

5:

我們應該儘量避免使用未初始化的指標,雖然指標可以不宣告時馬上定義,但是就像使用其他沒有初始化的變數一樣,在使用它的時候幾乎總會導致執行時崩潰。然而,導致崩潰的這一原因很難發現。

對大多數編譯器來說,如果使用未初始化的指標,會將指標中存放的不確定值視為地址,然後操縱該記憶體地址中存放的位內容。 

6
指標初始化和賦值操作的約束:

對指標進行以上操作只能使用一下四種類型的值:

1:0值常量表達式

2:型別匹配的物件的地址。

3:另一個物件之後的下一個地址。

4:同類型領一個有效指標。

7

特殊型別的指標:void*指標

它可以儲存任何型別物件的地址~

當然,不允許使用void*型別的指標操縱它所指向的物件。

※4.2.3

指標操作

指標提供間接操縱其所指物件的功能,與對迭代器進行解引用一樣,對指標進行解引用可以訪問它所指的物件,* 操作符將獲取指標所指的物件。

string s ( " hello  world " ) ;

string * SP = & s ;

cout << * sp;//   prints hello  world;

如果給你一個指標,要將指標所指的物件進行修改,可以怎樣做呢?

* SP =  “ good bye ” ;

這樣指標所指的物件就改成了 “ good bye ” ,也沒啥難度是吧。。。

※  注意給指標賦值或通過指標進行賦值:

對於初學的人來說,如何區分是給指標賦值還是通過指標進行賦值確實是挺困難的,不過我們可以記住一個重要的方法: 如果對左操作符進行了解引,那麼就是修改指標所指物件的值,如果沒有使用解引用,那麼就是修改指標本身。

考慮下面這個例子:

string  s1 (  " some value " ) ;

string *sp1=&s1;

string s2 ( " another " ) ;

string *sp2=&s2;

*sp1="  a new  value " ;

//  這裡修改了s1的值。

sp1= sp2;

//  這裡修改了sp1的指標,使其和sp2指向相同的物件。

※在這裡順便進行一下指標和引用的比較

雖然兩者都可以間接訪問另一個值,但是它們有兩個重要的區別:

1: 定義引用時沒有初始化是錯誤的;

2: 給引用賦值修改的是該引用所關聯的物件,因為它是物件的別名,。

4.3  c風格字串

2.2節中我們已經用過了字串字面值,並瞭解了字串的型別就是字串常量的陣列,現在可以更明確地認識到:它是一個 const char型別的陣列,c++從c語言繼承下來的一種通用結構是  c風格字串,而字串字面值就是這種型別的例項,然而,c風格字串既不能確切的歸結為c的型別,也不能歸結為c++,它是以空字元NULL結束的字元陣列。