第4章:數組和指針

轉載請註明原文出處:http://blog.csdn.net/roddick621

以下的知識點全部都是來自於C++ Primer 第四版,如果需要詳細瞭解的話,可以查看原版的書籍。


C++提供了兩種類似於vector和迭代器類型的低級符合類型——數組和指針。與vector類型相似,數組也可以保存某種類型的一組對象;而他們的區別在於,數組的長度是固定的。數組已經創建,就不允許添加新的元素。指針則可以想迭代器一樣用於遍歷和檢查數據中的元素。


1.數組

數組是由類名,表舒服和維數組成的符合數據類型,類型名規定了存放在數組中的元素類型,而維數則指定了數組中包含的元素個數。


1.1 數組的定義和初始化

數組的維數必須用值大於等於1的常量表達式定義。此常量表達式只能包含整形字面值常量、枚舉常量或者用常量表達式初始化的整型const對象。非const變量以及要到運行階段才知道其值的const變量都不能用於定義數組的維數。數組的維數必須在[]內指定,eg: int buffer[1024];

1.顯示初始化數組元素

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

int ia[3] = {0,1,2};
如果沒有顯式提供元素初值,則數據元素會像普通變量一樣初始化:

  • 在函數體外定義的內置數組,起元素均初始化問爲0;
  • 在函數體內定義的內置數組,起元素無初始化;
  • 不管數組在哪裏定義,如果其元素爲類類型,則自動調用該類的默認構造函數進行初始化

顯示初始化數據不需要指定數組的維數值:eg int ia[] = { 0, 1, 2} ;

如果指定了數組維數,那麼初始化列表提供的元素個數不能超過維數值。

2.當用一個字符串字面值進行初始化的時候,會在字符串字面值的尾端包含一個空字符(null)用於結束字符串。

char cal1[] = {'c','+', '+' }; //尾端沒有空字符
char cal2[] = {'c','+', '+', '\0' }; //尾端有空字符
char cal3 = "C++"; //與cal2相同,尾端默認添加空字符

3.與vector不同,一個數組不能用另外一個數組來初始化,也不能講一個數組複製給另一個數組。

1.2 數組操作

與vector元素一樣,數組元素可以用下標操作符來訪問,數組元素也是從0開始計數。

在用下標訪問元素時,vector使用vector::size_type作爲下標的類型,而數組下標的正確類型是size_t。在使用數組時,必須保證下標值在正確範圍之內。


2.指針的引入

指針是指向某種類型對象的複合數據類型,是用於數組的迭代器:指向數組中的一個元素。在指向數組元素的指針上使用解引用操作符和自增操作符,與在迭代器上的用法類似。


2.1 什麼是指針

指針的概念很簡單:指針用於指向對象。具體來說,指針保存的是另一個對象的地址。


2.2 指針的定義和初始化

每個指針都有一個與之關聯的數據類型,該數據類型決定了指針所指向的對象的類型。

1.指針變量的定義:C++語言使用*符號把一個標識符聲明爲指針:

2.3 指針操作

指針提供簡介操作其所指對象的功能。與迭代器一樣,對指針進行解引用可訪問它所指的對象,*操作符(解引用操作符)講獲取指針所指的對象。

1.生成左值的解引用操作。解引用操作符返回指向對象的左值,利用這個功能可以修改指針所指對象的值。

2.指針和引用的比較。雖然使用引用和指針都可以簡介訪問另一個值,但他們之間有兩個重要的區別。第一個區別在於引用永遠指向某個對象,定義引用時沒有初始化是錯誤的。第二個重要區別擇食賦值行爲的差異:給引用賦值修改的是該引用所關聯的對象的值,而不是使引用與另外一個對象關聯。引用一經初始化,就始終指向同一個特定對象(這就是爲什麼引用必須在定義時初始化的原因)。

3.指向指針的指針。指針本身也是可用指針指向的內存對象。這真佔用內存空間存放其值,因此指針的存儲地址可存放在指針中。eg: 

int ival = 1024;
int *pi = &ival;  // pi points to an int
int **ppi = &pi  // ppi point to a pointer to int

2.4 使用指針訪問數組元素。

C++語言中,指針和數組密切相關。特別是在表達式中使用數組名時,該名字會自動轉換問指向數組第一個元素的指針,eg: int ia[] = {0,2}; int *ip=ia;

1.指針的算術操作。 使用指針的算術操作在指向某個元素的指針上加上(或減去)一個整型數值,就可以計算出指向數組另一個元素的指針值。指針相減操作結果是標準庫類型ptrdiff_t數據類型。ptrdiff是signed整型。

2.解引用和指針算術操作之間的相互作用。在指針上加上一個整型數值,其結果仍然是指針。允許在這個結果上直接引用操作,而不必先把它賦給一個新指針。

3.下標和指針。使用下標訪問數組時,實際上是使用下標訪問指針。只要指針指向數組元素,就可以對它進行下標操作:

int *p = &ia[2]; //p指向ia[2]
int j = p[1] ; //j 的值等於ia[3]
int k = p[-2] ; // k的指爲ia[0]
4.計算數組的超出末端指針。與vector提供的end操作類似,可以計算出數組的超出末端指針的值。

int arr [arr_size] = {1,2,…}; 
int *p = arr ;
int *p2 = p +arr_size;  
這個p2值能夠用來與其他指針比較,或者用來做指針算術操作表達式的操作數。對p2進行解引用講得到無效值。

5.輸出數組元素。C++允許使用指針遍歷數組。與其他內置類型一樣,數組也沒有成員函數。因此,數組不提供begin和end操作,所以只能自己給指針定位,使之分別標誌數組的其實位置和超出末端位置。

6.指針是數組的迭代器。內置數組類型具有標準庫容器的許多性質,與數組聯合使用的指針本身就是迭代器。


2.5 指針和const限定符

1.指向const對象的指針。 如果指針指向const對象,則不允許用指針來該表其所指的const值。爲了保持這個特性,C++語言強制要求指向const對象指針也必須具有const特性。

const double *cptr;  // cptr是指向const double類型的指針
const double pr = 3.14
double *ptr = &pr ; //錯誤,ptr沒有const特性
const double *cptr = ≺ //正確。
const void *cpr = &pr ; //必須用const void* 類型的指針來保存const對象的指針,不能用void*指針。
//允許把const對象的地址賦給指向const對象的指針。
double dval=3.14;
cptr = &dval; //但是任何通過指針cptr修改其值的行爲都會導致編譯時的錯誤。


2.const指針。const指針本身的值不能修改。

int errNumb = 0;
int *const curErr = &errNumb; //curErr是指向int類型對象的const指針。
與其他const變量一樣,const指針的值不能修改,const指針與任何const變量一樣,也必須在定義時初始化。指針本身是const的事實並沒有說明是否能使用該指針去修改它所指向對象的值,指針所指對象的值能夠修改完全取決於該對象的類型。

3.指向const對象的const指針。它既不能修改pi_ptr所指向對象的值,也不能修改該指針的指向。

const double pr = 3.141519 
const double *const pr_ptr = &pr ; //pi_ptr首先是一個const指針,指向double類型的const對象。

4.指針和typedef
typedef string *pstring;
const pstring cstr;

聲明const pstring時,const修飾的是pstring的類型,這是一個指針。因此,該聲明語言應該是把cstr定義爲指向string類型對象的const指針,等價於:string *const cstr;

3.C風格字符串

C風格字符串就是以空字符null結束的字符數組。

1.C風格字符串的使用。C++語言通過(const) char *類型的指針來操縱C風格字符串。一般來說,可以使用指針的算術操作來遍歷C風格字符串,每次都對指針進行測試並遞增1,知道遇到結束符null爲止。

2.C風格字符串的標準庫函數。要使用這些標準庫,必須包含對應的頭文件 : #include <cstring>  cstring是string.h頭文件的C++版本,而string.h則是C語言提供的標準庫。

操縱C風格字符串的標準庫函數
strlen(s) 返回s的長度,不包括字符串結束符null
strcmp(s1,s2) 比較兩個字符串s1和算s2是否相同。若s1與s2相等,返回0;若s1大於s2,返回正數,若s1小於s2,則返回負數。
strcat(s1,s2) 將字符串s2連接到s1後,並返回s1。
strcpy(s1,s2) 講s2複製給s1,並返回s1。
strncat(s1, s2, n0)                  講s2的前n個字符連接到s1後面,並返回s1。
strncpy(s1, s2, n) 將s2的前n個字符複製給s1,並返回s1。
傳遞給這些標準庫例程的指針必須具有非零值,並且指向以null結束的字符數組中的第一個元素。其中一些標準庫函數會修改傳遞給它的字符串,這些函數講假定他們所修改的字符串具有足夠大的空間接受本函數新生成的字符,程序員必須確保目標字符足夠大。

3.永遠不要忘記字符串結束符null。標準庫函數總是需要字符串以null爲結束符的,否則計算的結果不可預料。

4.調用者必須確保目標字符串具有足夠的大小。

5.使用strn函數處理C風格字符串。進行操作的時候需要正確計算出size實參的值,這樣strn版本要比沒有size參數的版本更加安全,但是要想目標數組複製貨串接比其size更多的字符,數組溢出的現象仍然會發生。

6.儘可能使用標準庫類型string。

3.1 創建動態數組

動態數組不必在編譯的時候知道其長度,可以在運行的時候才確定數組長度。與數組變量不同,動態分配的數組將一直存在,知道程序顯式釋放它爲止。每個程序在執行時都佔用一塊可用的內存,用於存放動態分配的對象,次內存空間稱爲程序的自由存儲區(free store)堆(heap)。C語言使用malloc和free來分配,C++則使用new和delete來實現相同的功能。

1.動態數組的定義。數組變量通過指定類型,數組名和維數來定義。而動態分配數組時,只需要指定類型和數組長度,不必爲數組對象命名,new表達式返回指向新分配數組的第一個元素的指針:int *pia = new int[10];   

2.初始化動態分配的數組。動態分配數組時,如果數組元素具有類類型,則使用默認構造函數來初始化;如果數組元素是內置類型,則無初始化。也可以使用跟在數組藏毒後面的一堆空圓括號,對數組元素做初始化:

string *psa = new string[10] //初始化爲空
int *pia = new int[10];  //沒有初始化
int  *pia2 = new int[10](); //初始化爲默認值
對於動態分配的數組,其元素值可以初始化爲該類型的默認值,而不能想數組變量一樣,用初始化列表進行初始化。

3.const對象的動態數組。

如果在自由存儲區中創建的數組存儲了內置類型的const對象,則必須爲這個數組提供初始化,因爲數組元素都是const對象,無法賦值。

4.允許動態分配空數組。用new穿件長度爲0的數組時,new返回有效的非零指針。該指針與new返回的其他指針不同,不能進行解引用操作,因爲它畢竟沒有指向任何元素。而允許比較運算,加(減)0運算。

5.動態空間的釋放。動態分配的內存最後必須進行釋放,否則內存將會被耗盡。程序員必須顯式地用delete []來釋放不在需要使用到的動態數組的內存空間。eg:delete [] pid;  這裏的空方括號是必不可少的,它告訴編譯器該指針指向的是自由存儲區中的數組,而非單個對象。


3.2 新舊代碼的兼容

1.混合使用標準庫string和C風格字符串。

  • 可以使用C風格字符串對string對象進行初始化或賦值。
  • string類型的加法操作需要兩個操作數,可以使用C風格字符串作爲其中的一個操作數,也允許將C風格字符串作符合賦值操作的右操作數。

反之則不成立:在要求C風格字符串的地方不可以直接使用標準庫string類型對象。但是string類提供了一個名爲c_string的成員函數實現我們的要求:

string st3("Helloworld");
const char *str = st3.c_str() ; //因爲c_str返回的指針指向const char類型的數組。


2.使用數組初始化vector對象。使用數組初始化vector對象的時候,必須支出用於初始化的第一個元素已經數組最後一個元素的下一位置的地址:

const size_t arr_size = 6;
int int_arr[arrsize] = {0,1,2,3,4,5}
vector<int> ivec(int_arr,int_arr+arr_size);

4.多維數組

嚴格地說,C++中並沒有多維數組,通常所指的多爲數組就是數組的數組。

1.多維數組的初始化。與普通數組一樣,但是對多維數組的每一行,可以再用花括號指定其元素的初始化式。

2.多爲數組的下標引用。爲了多多維數組進行索引,每一維都西藥一個下標。

3.指針和多爲數組。與普通數組一樣,使用多維數組名時,實際上將其自動轉換爲指向該數組第一個元素的指針。定義指向數組的指針與如何定義數組本身類似:首先聲明元素類型,後接(數組)變量名字和維數。

int ia[3][4];
int (*ip)[4]; //指向大小爲4的int型數組
int *ip1[4]; //Ip1爲一個數組,保存int型指針,所以這裏的()是必須加的。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章