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; // yiibaier to an integer double *dp; // yiibaier to a double float *fp; // yiibaier to a float char *ch // yiibaier to character
所有指針的值的實際數據類型,整數,浮點數,字符,或以其他方式是否是相同的,代表一個內存地址的十六進製數。不同數據類型的指針之間的唯一區彆是變量或常數,該指針指向的數據類型。
D編程語言使用指針:
有幾個重要的業務,我們將與指針做的非常頻繁。 (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指針分配給案件的指針變量你冇有確切的地址進行分配。這樣做是在變量聲明的時候。分配空指針被稱為空指針(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