140 likes | 295 Views
第八章 指標. 8-1 指標 8-2 動態變數與陣列 8-3 綜合範例. 第八章 指標. 截至目前為止,我們介紹的資料型別有 2-3 節基本資料型別、第七章的陣列型別及結構型別,本章 8-1 節將介紹另一個進階資料型別,稱為指標 (Pointer) 。筆者也將在 8-2 節中說明如何使用指標及 malloc( ) 函式,以便在執行階段動態的配置記憶體。. 8-1 指標. 指標型別是所有高階語言所沒有的資料型別,它的優點是指標型別直接 與記憶體打交道,如此可以提升程式的執行效率。 指標型別的宣告
E N D
第八章 指標 • 8-1 指標 • 8-2 動態變數與陣列 • 8-3 綜合範例
第八章 指標 截至目前為止,我們介紹的資料型別有2-3節基本資料型別、第七章的陣列型別及結構型別,本章8-1節將介紹另一個進階資料型別,稱為指標(Pointer)。筆者也將在8-2節中說明如何使用指標及malloc( )函式,以便在執行階段動態的配置記憶體。
8-1 指標 指標型別是所有高階語言所沒有的資料型別,它的優點是指標型別直接 與記憶體打交道,如此可以提升程式的執行效率。 指標型別的宣告 指標型別的宣告比較特殊,它必須藉助一種指標運算子(*),其宣告語 法如下: 資料型別 *指標變數; 資料型別可以是3-2節的基本資料型別,指標變數可以是一個合法的變數 名稱。例如,以下式子即宣告ptr是一個整數的指標變數。 int *ptr; 經過以上宣告之後,ptr即可指向任一整數變數位址,例如, int a=5; prt = &a;
則ptr指向整數a的位址,往後即可使用*ptr代表整數a。例如,以下敘述則ptr指向整數a的位址,往後即可使用*ptr代表整數a。例如,以下敘述 可印出*ptr的值。 printf (“%d”, *ptr); 若硬要印出ptr的值,如以下敘述: printf (“%d”, ptr); 則沒有意義了。因為ptr的值會隨著不同的機器與不同的執行次數而有不 同的值。所以,在指標型別中,我們並不在意ptr所在位址,在意的是*ptr 的值。
指標與一維陣列 接著我們要談如何使用指標型別存取陣列的值。例如,程式中若包含以 下的宣告: int *ptr; int a[5]={3, 8, 6, 2, 5}; ptr = a; 或 ptr = &a[0]; 則表示宣告ptr是一種指標型別,ptr本身是一個位址,*ptr才是一個值, 其中ptr=a的效果就是將ptr指向a[0]的位址,&符號是取址的意思。所以 若經以上設定, printf(“%d”, *ptr); 將可得3,若要得下一個陣列值,則應將指標向後移一個位置,例如: ptr++; /* ptr=ptr+1 */ printf(“%d”, *ptr); 或 printf(“%d”, ptr[1]); 均可得到結果8。其次,上式若只純粹取值,亦可以下式表示: printf(“%d”, *(ptr+1));
範例8-1a 同範例7-1c,但改用指標型別處理陣列的值。 範例8-1b 請以指標型別重做泡沫排序法。
指標與二維陣列 二維陣列在人們眼中通常用於處理二維的行列表格,但電腦內部的記憶 體中,是以一維的方式排列,所以雖然是二維的陣列,但在電腦記憶體 中已轉為一維的方式儲存,二維陣列以指標處理的步驟是先指定第一元 素給指標變數,如下所示: int *ptr, a[4][3]; ptr = &a[0][0]; /* 不能寫成ptr=a */ 其次,若要存取其值,只要使用陣列名稱與適當的位移即可。例如,以 下敘述可設定第i列第j行元素等於5。 *( *(a+i ) + j) =5; /* 不能寫成 * ( *ptr+i ) + j = 5 */ 上式若要以ptr表示,則應使用以下敘述將二維排列轉為一維的直線 列,其中3是第一維的行個數。 *( ptr + 3*i + j ) =5; /* 不能寫成 * ( a + 3*i + j ) = 5 */
以上敘述將二維的列與行轉為一維的直線排列,如下表所示,括號內為以上敘述將二維的列與行轉為一維的直線排列,如下表所示,括號內為 二維(列、行),括號外的為一維直線的位移量。 範例8-1c 請以指標重做範例7-1g的學生成績統計。
8-2 動態變數與陣列 變數與陣列除了可於設計階段佈置外,亦可於執行階段再產生,於設計 階段所佈置好的變數或陣列稱為靜態變數或陣列;於執行階段產生的, 則稱為動態變數或陣列。為什麼要有動態變數或陣列呢?那是因為有些情 況,於程式設計階段,並不知道要預留多大的陣列,若不管使用者所需 要的陣列大小為何,通通宣告一個最大值,則非常浪費記憶體,此時即 可使用本節所要介紹的動態變數與陣列。本節將介紹如何利用指標及簡 單的malloc( )函式,動態的取得程式執行時所需的記憶體。 • 動態變數及陣列使用步驟有三:宣告變數及陣列、動態產生變數及陣列、以及動態變數及陣列的存取,最後是釋放動態記憶體。分別說明如下:
宣告變數及陣列變數 動態陣列變數的宣告同一般陣列,如以下敘述可宣告一個edi變數,其型 別為int。 int * edi; 以下敘述,可宣告一個edi變數,其型別為pData。 pData * edi; pData型別定義如下: struct pData { char *name; int age; }; 以下敘述可宣告一個edi陣列變數,其型別為pData。 pData * edi[2]; 以下敘述可宣告一個edi的二維陣列,其型別為pData。 pData * edi[3][2];
動態產生變數及陣列 使用標頭檔<stdlib.h>中已宣告的malloc( )函式及free( )函式,於程式執 行時直接向記憶體要空間及釋放空間。 如果陣列有100個int,我們就必須明白的告訴記憶體100個int需要多少個 bytes,如下列程式片段所示: edi = malloc ( n * sizeof(int) ); /* n=100 */ 釋放記憶體 由於動態陣列是在程式執行時,直接向記憶體要求取得的,因此在程式 結束前,必須釋放出所取得的記憶體,如下所示。 free (edi); 存取動態陣列 動態陣列的使用與上節所介紹的指標存取相同,值得注意的是,動態向 記憶體要求取得的記憶體時並沒有進行初始化的動作,所配置到的記憶 體預設值不一定為0,因此在使用動態陣列時,要特別注意初始值的設 定。
範例8-2a 示範動態變數的用法。 範例8-2b 示範動態陣列的使用。本例於設計階段並不知使用者所要輸入的個數, 所以採用動態陣列逐一配置記憶體。 範例8-2c 示範動態一維陣列的產生及資料的存取。 範例8-2d 示範動態二維陣列的產生。 範例8-2e 示範兩個矩陣相加。
8-3 綜合範例 矩陣相乘 若有矩陣A23如下,我們稱為2列3行、記為A23,其中共有6個元素,每 個元素編號如下: A23 = a11 a12 a13 a21 a22 a23 矩陣要能進行相乘,必須第一個矩陣的行數等於第二個矩陣的列數,且 相乘結果的列數要等於第一個矩陣的列數;結果的行數等於第二個矩陣 的行數。如下式為A矩陣乘以B矩陣的行列數目表示法。 Anm × Bmp = Cnp 其次,若有矩陣如下 : Cnp = Anm × Bmp 則任一子集合Cnp如下: m Cnp = Ank × Bkp k=1
範例8-3 示範矩陣相乘。