D編程指針既簡單又有趣,使用指針可以更輕松地執(zhí)行某些任務,而沒有它們則無法執(zhí)行其他任務(如動態(tài)內(nèi)存分配),一個簡單的指針如下所示。
import std.stdio;
void main () {
int var1;
writeln("Address of var1 variable: ",&var1);
char var2[10];
writeln("Address of var2 variable: ",&var2);
}
編譯并執(zhí)行上述代碼后,將產(chǎn)生以下輸出-
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
所有指針的值的實際數(shù)據(jù)類型(無論是整數(shù),浮點數(shù),字符還是其他形式)都是相同的,即表示內(nèi)存地址的十六進制數(shù)字,不同數(shù)據(jù)類型的指針之間的唯一區(qū)別是指針指向的變量或常量的數(shù)據(jù)類型。
當我們非常頻繁地使用指針時,很少有重要的操作。
這是通過使用一元運算符 * 完成的,該運算符返回位于變量操作數(shù)指定地址處的變量的值。以下示例利用這些操作-
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);
}
編譯并執(zhí)行上述代碼后,將產(chǎn)生以下輸出-
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) ;
}
編譯并執(zhí)行上述代碼后,將產(chǎn)生以下輸出-
The value of ptr is null
在大多數(shù)操作系統(tǒng)上,不允許程序訪問地址0處的內(nèi)存,因為該內(nèi)存是由操作系統(tǒng)保留的,然而;存儲器地址0具有特殊的意義;它指示指針不旨在指向可訪問的存儲位置。
按照慣示例,如果指針包含空(零)值,則假定該指針不指向任何內(nèi)容。要檢查空指針,可以使用以下if語句-
if(ptr) //succeeds if p is not null
if(!ptr) //succeeds if p is null
因此,如果為所有未使用的指針賦予了空值,并且避免了使用空指針,則可以避免意外誤用未初始化的指針。
可以在指針上使用四種算術(shù)運算符:++,--,+和-
為了理解指針算術(shù),讓我們考慮一個名為 ptr 的整數(shù)指針,該指針指向地址1000。假設32位整數(shù),讓我們對指針執(zhí)行以下算術(shù)運算-
ptr++
那么 ptr 將指向位置1004,因為每次ptr遞增時,它都指向下一個整數(shù)。該操作會將指針移動到下一個存儲位置,而不會影響該存儲位置的實際值。
如果 ptr 指向地址為1000的字符,則上述操作將指向位置1001,因為下一個字符將在1001處可用。
我們更喜歡在程序中使用指針而不是數(shù)組,因為變量指針可以遞增,這與數(shù)組名不同,因為數(shù)組名是常量指針,因此不能遞增。以下程序遞增變量指針以訪問數(shù)組的每個后續(xù)元素-
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);
}
}
編譯并執(zhí)行上述代碼后,將產(chǎn)生以下輸出-
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
指針和數(shù)組密切相關(guān),但是,指針和數(shù)組不能完全互換。如,考慮以下程序-
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一起使用。
編譯并執(zhí)行上述代碼后,將產(chǎn)生以下輸出-
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);
}
編譯并執(zhí)行上述代碼后,將產(chǎn)生以下輸出-
Value of var :3000
Value available at *ptr :3000
Value available at **pptr :3000
D允許您將指針傳遞給函數(shù)。為此,它只是將函數(shù)參數(shù)聲明為指針類型。
下面的簡單示例將指針傳遞給函數(shù)。
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;
}
將以上代碼編譯在一起并執(zhí)行后,將產(chǎn)生以下輸出-
Average is :214.4
考慮以下函數(shù),該函數(shù)使用指針返回10個數(shù)字,表示第一個數(shù)組元素的地址。
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];
}
編譯并執(zhí)行上述代碼后,將產(chǎn)生以下輸出-
*(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
數(shù)組名稱是指向數(shù)組第一個元素的常量指針。因此,在聲明中-
double balance[50];
balance是指向&balance [0]的指針,它是數(shù)組balance的第一個元素的地址。因此,以下程序片段為p分配了balance的第一個元素的地址-
double *p;
double balance[10];
p=balance;
將數(shù)組名稱用作常量指針是合法的,反之亦然。因此,*(balance + 4)是訪問balance [4]數(shù)據(jù)的合法方法。
一旦將第一個元素的地址存儲在p中,就可以使用* p,*(p + 1),*(p + 2)等訪問數(shù)組元素。以下示例顯示了上面討論的所有概念-
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));
}
}
編譯并執(zhí)行上述代碼后,將產(chǎn)生以下輸出-
Array values using pointer
*(p + 0) : 1000
*(p + 1) : 2
*(p + 2) : 3.4
*(p + 3) : 17
*(p + 4) : 50
更多建議: