1. 雙重指標
雙重指標顧名思義就是存放另一個指標在記憶體中的位址。可以透過以下語法宣告:
int **dptr; // or int *(*dptr)
//將dptr指向另一個指標
int a = 10, *ptr;
ptr = &a;
dptr = &ptr;
2. 二維陣列 & 雙重指標
在前篇基本指標 Pointer (Part.1)中,我有提到一為陣列的名稱是一個指向陣列位址的指標常數(Pointer Constant),而二維陣列的概念可視為其的延伸。
假設我們宣告一個二維陣列
int a[3][4];
可以將a視為是三個一維陣列的組合,而指向這三個一維陣列位址的指標常數分別是a[0]、a[1]和a[2]
而a
則是一個雙重指標常數,它指向由a[0]、a[1]和a[2]
組成的指標常數陣列的位址。
用指標存取二維陣列可以靠指標的運算達成:
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
for(int m=0;m<3;m++){
for(int n=0;n<4;n++){
cout << *(*(a+m)+n) << ' ';
}
}
可以看到第5行我們直接使用a這個指標常數進行運算,而我們可以得到以下結論:
*(*(a+m)+n); //等於用指標表示a[m][n]
此外,函數的輸入不接受雙重指標,故如果想傳遞多維陣列到函式中,則需要使用
void Func(int [3][4]); //宣告
void Func(int a[3][4]){} //函式內容
3. 動態記憶體配置
C++基本資料型態(如int,float,char...)都是在編譯時完成記憶體的配置,他們會占用固定的記憶體空間,這種記憶體配置方式稱為「靜態記憶體配置(static memory allocation)」。
相對的,在執行期間能夠彈性調派記憶體的方式稱為「動態記憶體配置(dynamic memory allocation)」,使用動態記憶體配置時,OS會在程式執行時額外尋找一塊記憶體空間供程式使用,這個未用空間(free space)稱為記憶堆(heap)。
4. 動態記憶體配置實作
動態記憶體配置的實作,不外乎的和指標有關。基本資料的動態配置基本上就是由該資料型態的指標指向記憶堆,搭配new
和delete
運算子
int *ptr;
ptr = new int;
*ptr = 10; //使用ptr
當使用new
運算子配置記憶體時,會導致記憶體一直被占用,直到電腦關閉為止,因此,必須使用delete
運算子來釋放記憶體空間,並將ptr指向的值設為NULL
以保證指標使用的安全性
//ptr使用完後
delete ptr;
ptr = NULL;
接著就要進入重點,C++中最常使用動態記憶體配置的資料結構就屬陣列,陣列常常會造成記憶體空間的浪費,因此使用動態配置就能達到最有效的使用。
int *ptr;
ptr = new int[5]{ 1, 2, 3, 4, 5 };
for(int i=0;i<5;i++){
cout<<ptr[i]<<endl;
}
delete[] ptr;
ptr = NULL;
輸出結果
1
2
3
4
5
p.s. 字串的動態配置,std::string
有提供內置的動態記憶體配置,在程式運行超出它的scope時就會自動釋放。
5. 指標、參照和函式
首先,先介紹參照(reference)。參照簡單來說就是一個變數的別名,變數和它的參照除了名子以外,記憶體位置和值都是相同的,所以基本上就是一樣的東西。與指標不同,參照在被宣告時就必須被初始化,而且設定後便無法改變參考的對象。
int a=10;
int &ref = a;
既然連記憶體位址都和原本的變數一模一樣,那為什麼需要參照呢?參照的主要功能在於函數的引數傳遞,因為是別名,所以可以避免複製大量的變數到函數去。
引數在函數間的傳遞方式有三種,第一種是最簡單的傳值(pass by value),第二種是前面有提到的透過位址當作引數傳遞,第三種就是就是此段要介紹的用參照作為引數傳遞。
void refFunc(int &);
int main(void){
int a =10;
refFunc(a);
cout << "In main function: " << a << endl;
system("pause");
return 0;
}
void refFunc(int &a){
a += 1;
cout << "In refFunc(): " << a << endl;
}
輸出結果
In refFunc(): 11
In main function: 11
傳遞參照(Pass-by-reference)相對於傳值(Pass-by-value)是更有效率的方法,因為函數在使用引數時不需要將引數物件再進行複製。而且使用參照能夠在該函數內對變數的值做更動,相對於傳值來說在某些狀況下更加便捷。而用指標傳遞則是一個相對差的做法。這篇文章中有對於參照和指標,以及在何種情況應用哪種方法的詳細介紹,有興趣可以去看看。
6. 結語
我還是一無所知