
- D 程式設計基礎
- D 程式設計 - 首頁
- D 程式設計 - 概述
- D 程式設計 - 環境
- D 程式設計 - 基本語法
- D 程式設計 - 變數
- D 程式設計 - 資料型別
- D 程式設計 - 列舉
- D 程式設計 - 字面量
- D 程式設計 - 運算子
- D 程式設計 - 迴圈
- D 程式設計 - 條件語句
- D 程式設計 - 函式
- D 程式設計 - 字元
- D 程式設計 - 字串
- D 程式設計 - 陣列
- D 程式設計 - 關聯陣列
- D 程式設計 - 指標
- D 程式設計 - 元組
- D 程式設計 - 結構體
- D 程式設計 - 聯合體
- D 程式設計 - 範圍
- D 程式設計 - 別名
- D 程式設計 - 混入
- D 程式設計 - 模組
- D 程式設計 - 模板
- D 程式設計 - 不可變性
- D 程式設計 - 檔案 I/O
- D 程式設計 - 併發
- D 程式設計 - 異常處理
- D 程式設計 - 合同
- D - 條件編譯
- D 程式設計 - 面向物件
- D 程式設計 - 類與物件
- D 程式設計 - 繼承
- D 程式設計 - 過載
- D 程式設計 - 封裝
- D 程式設計 - 介面
- D 程式設計 - 抽象類
- D 程式設計 - 有用資源
- D 程式設計 - 快速指南
- D 程式設計 - 有用資源
- D 程式設計 - 討論
D 程式設計 - 指標
D 程式設計指標易於學習且趣味十足。一些 D 程式設計任務使用指標更容易完成,而其他 D 程式設計任務(例如動態記憶體分配)則無法在沒有指標的情況下完成。下面顯示了一個簡單的指標。

指標並非直接指向變數,而是指向變數的地址。眾所周知,每個變數都是一個記憶體位置,每個記憶體位置都有其定義的地址,可以使用表示記憶體地址的取地址符 (&) 運算子訪問。考慮以下列印已定義變數地址的程式碼:
import std.stdio; void main () { int var1; writeln("Address of var1 variable: ",&var1); char var2[10]; writeln("Address of var2 variable: ",&var2); }
編譯並執行上述程式碼後,將產生以下結果:
Address of var1 variable: 7FFF52691928 Address of var2 variable: 7FFF52691930
什麼是指標?
指標是一個變數,其值是另一個變數的地址。像任何變數或常量一樣,必須在使用指標之前宣告它。指標變數宣告的一般形式為:
type *var-name;
這裡,type 是指標的基本型別;它必須是有效的程式設計型別,而 var-name 是指標變數的名稱。用於宣告指標的星號與用於乘法的星號相同。但是,在此語句中,星號用於將變數指定為指標。以下是有效的指標宣告:
int *ip; // pointer to an integer double *dp; // pointer to a double float *fp; // pointer to a float char *ch // pointer to character
所有指標的實際資料型別,無論是整數、浮點數、字元還是其他型別,都是相同的,即表示記憶體地址的長十六進位制數。不同資料型別指標之間的唯一區別在於指標指向的變數或常量的型別。
在 D 程式設計中使用指標
使用指標時,有一些重要的操作。
我們定義指標變數
將變數的地址賦給指標
最後訪問指標變數中地址的值。
這是透過使用一元運算子 * 來完成的,它返回位於其運算元指定的地址處的變數的值。以下示例使用了這些操作:
import std.stdio; void main () { int var = 20; // actual variable declaration. int *ip; // pointer variable ip = &var; // store address of var in pointer variable writeln("Value of var variable: ",var); writeln("Address stored in ip variable: ",ip); writeln("Value of *ip variable: ",*ip); }
編譯並執行上述程式碼後,將產生以下結果:
Value of var variable: 20 Address stored in ip variable: 7FFF5FB7E930 Value of *ip variable: 20
空指標
如果您沒有確切的地址要賦值,則始終建議將指標賦值為 NULL。這是在變數宣告時完成的。賦值為空的指標稱為空指標。
空指標是在包括 iostream 在內的多個標準庫中定義的值為零的常量。考慮以下程式:
import std.stdio; void main () { int *ptr = null; writeln("The value of ptr is " , ptr) ; }
編譯並執行上述程式碼後,將產生以下結果:
The value of ptr is null
在大多數作業系統上,程式不允許訪問地址 0 處的記憶體,因為該記憶體由作業系統保留。但是,記憶體地址 0 具有特殊的意義;它表示指標並非旨在指向可訪問的記憶體位置。
按照約定,如果指標包含空(零)值,則假定它不指向任何內容。可以使用 if 語句檢查空指標,如下所示:
if(ptr) // succeeds if p is not null if(!ptr) // succeeds if p is null
因此,如果所有未使用的指標都被賦予空值,並且避免使用空指標,則可以避免意外錯誤地使用未初始化的指標。許多時候,未初始化的變數包含一些垃圾值,這使得程式除錯變得困難。
指標運算
有四個算術運算子可以用於指標:++、--、+ 和 -
為了理解指標運算,讓我們考慮一個名為 ptr 的整數指標,它指向地址 1000。假設 32 位整數,讓我們對指標執行以下算術運算:
ptr++
則 ptr 將指向位置 1004,因為每次遞增 ptr 時,它都會指向下一個整數。此操作將指標移動到下一個記憶體位置,而不會影響記憶體位置的實際值。
如果 ptr 指向地址為 1000 的字元,則上述操作指向位置 1001,因為下一個字元將在 1001 處可用。
遞增指標
我們更傾向於在程式中使用指標而不是陣列,因為變數指標可以遞增,而陣列名則不能遞增,因為它是一個常量指標。以下程式遞增變數指標以訪問陣列的每個後續元素:
import std.stdio; const int MAX = 3; void main () { int var[MAX] = [10, 100, 200]; int *ptr = &var[0]; for (int i = 0; i < MAX; i++, ptr++) { writeln("Address of var[" , i , "] = ",ptr); writeln("Value of var[" , i , "] = ",*ptr); } }
編譯並執行上述程式碼後,將產生以下結果:
Address of var[0] = 18FDBC Value of var[0] = 10 Address of var[1] = 18FDC0 Value of var[1] = 100 Address of var[2] = 18FDC4 Value of var[2] = 200
指標與陣列
指標和陣列密切相關。但是,指標和陣列並非完全可以互換。例如,考慮以下程式:
import std.stdio; const int MAX = 3; void main () { int var[MAX] = [10, 100, 200]; int *ptr = &var[0]; var.ptr[2] = 290; ptr[0] = 220; for (int i = 0; i < MAX; i++, ptr++) { writeln("Address of var[" , i , "] = ",ptr); writeln("Value of var[" , i , "] = ",*ptr); } }
在上述程式中,您可以看到 var.ptr[2] 用於設定第二個元素,而 ptr[0] 用於設定第零個元素。遞增運算子可用於 ptr,但不能用於 var。
編譯並執行上述程式碼後,將產生以下結果:
Address of var[0] = 18FDBC Value of var[0] = 220 Address of var[1] = 18FDC0 Value of var[1] = 100 Address of var[2] = 18FDC4 Value of var[2] = 290
指向指標的指標
指向指標的指標是多重間接定址或指標鏈的一種形式。通常,指標包含變數的地址。當我們定義指向指標的指標時,第一個指標包含第二個指標的地址,第二個指標指向包含實際值的位置,如下所示。

作為指向指標的指標的變數必須宣告為這種型別。這是透過在其名稱前面新增一個額外的星號來完成的。例如,以下是宣告指向 int 型別指標的指標的語法:
int **var;
當目標值由指向指標的指標間接指向時,訪問該值需要兩次應用星號運算子,如下面的示例所示:
import std.stdio; const int MAX = 3; void main () { int var = 3000; writeln("Value of var :" , var); int *ptr = &var; writeln("Value available at *ptr :" ,*ptr); int **pptr = &ptr; writeln("Value available at **pptr :",**pptr); }
編譯並執行上述程式碼後,將產生以下結果:
Value of var :3000 Value available at *ptr :3000 Value available at **pptr :3000
將指標傳遞給函式
D 允許您將指標傳遞給函式。為此,它只需將函式引數宣告為指標型別。
以下簡單示例將指標傳遞給函式。
import std.stdio; void main () { // an int array with 5 elements. int balance[5] = [1000, 2, 3, 17, 50]; double avg; avg = getAverage( &balance[0], 5 ) ; writeln("Average is :" , avg); } double getAverage(int *arr, int size) { int i; double avg, sum = 0; for (i = 0; i < size; ++i) { sum += arr[i]; } avg = sum/size; return avg; }
編譯並執行上述程式碼後,將產生以下結果:
Average is :214.4
從函式返回指標
考慮以下函式,它使用指標返回 10 個數字,這意味著第一個陣列元素的地址。
import std.stdio; void main () { int *p = getNumber(); for ( int i = 0; i < 10; i++ ) { writeln("*(p + " , i , ") : ",*(p + i)); } } int * getNumber( ) { static int r [10]; for (int i = 0; i < 10; ++i) { r[i] = i; } return &r[0]; }
編譯並執行上述程式碼後,將產生以下結果:
*(p + 0) : 0 *(p + 1) : 1 *(p + 2) : 2 *(p + 3) : 3 *(p + 4) : 4 *(p + 5) : 5 *(p + 6) : 6 *(p + 7) : 7 *(p + 8) : 8 *(p + 9) : 9
指向陣列的指標
陣列名是指向陣列第一個元素的常量指標。因此,在宣告中:
double balance[50];
balance 是指向 &balance[0] 的指標,它是陣列 balance 的第一個元素的地址。因此,以下程式片段將 p 賦值為 balance 的第一個元素的地址:
double *p; double balance[10]; p = balance;
將陣列名用作常量指標以及反過來都是合法的。因此,*(balance + 4) 是訪問 balance[4] 處資料的合法方法。
一旦將第一個元素的地址儲存在 p 中,就可以使用 *p、*(p+1)、*(p+2) 等訪問陣列元素。以下示例顯示了上述所有概念:
import std.stdio; void main () { // an array with 5 elements. double balance[5] = [1000.0, 2.0, 3.4, 17.0, 50.0]; double *p; p = &balance[0]; // output each array element's value writeln("Array values using pointer " ); for ( int i = 0; i < 5; i++ ) { writeln( "*(p + ", i, ") : ", *(p + i)); } }
編譯並執行上述程式碼後,將產生以下結果:
Array values using pointer *(p + 0) : 1000 *(p + 1) : 2 *(p + 2) : 3.4 *(p + 3) : 17 *(p + 4) : 50