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; // yiibaier to an integer double *dp; // yiibaier to a double float *fp; // yiibaier to a float char *ch // yiibaier to character
所有指標的值的實際資料型別,整數,浮點數,字元,或以其他方式是否是相同的,代表一個記憶體地址的十六進位制數。不同資料型別的指標之間的唯一區別是變數或常數,該指標指向的資料型別。
有幾個重要的業務,我們將與指標做的非常頻繁。 (a)我們定義一個指標變數(b)分配一個變數的地址的指標(c)在指標變數中可用的地址最終進入的值。這是通過使用一元運算子*,返回位於其運算元指定的地址變數的值來完成。下面的範例使用這些操作:
import std.stdio; void main () { int var = 20; // actual variable declaration. int *ip; // yiibaier variable ip = &var; // store address of var in yiibaier 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指標分配給案件的指標變數你沒有確切的地址進行分配。這樣做是在變數宣告的時候。分配空指標被稱為空指標(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是一個整數的指標,假設它32位元指向的地址1000整數,讓我們上的指標執行以下算術運算:
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],這是陣列平衡的第一個元素的地址。因此,下面的程式片段分配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 yiibaier " ); for ( int i = 0; i < 5; i++ ) { writeln( "*(p + ", i, ") : ", *(p + i)); } }
讓我們編譯和執行上面的程式,這將產生以下結果:
Array values using yiibaier *(p + 0) : 1000 *(p + 1) : 2 *(p + 2) : 3.4 *(p + 3) : 17 *(p + 4) : 50