D編程指針既簡(jiǎn)單又有趣,使用指針可以更輕松地執(zhí)行某些任務(wù),而沒有它們則無法執(zhí)行其他任務(wù)(如動(dòng)態(tài)內(nèi)存分配),一個(gè)簡(jiǎn)單的指針如下所示。
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
指針是一個(gè)變量,其值是另一個(gè)變量的地址,像任何變量或常量一樣,必須先聲明一個(gè)指針,然后才能使用它。指針變量聲明的一般形式是-
type *var-name;
在這里, type 是指針的基本類型,它必須是有效的編程類型,并且 var-name 是指針變量的名稱,用于聲明指針的星號(hào)與用于乘法的星號(hào)相同,然而;在此語句中,星號(hào)用于將變量指定為指針。以下是有效的指針聲明-
int *ip; //pointer to an integer
double *dp; //pointer to a double
float *fp; //pointer to a float
char *ch //pointer to character
所有指針的值的實(shí)際數(shù)據(jù)類型(無論是整數(shù),浮點(diǎn)數(shù),字符還是其他形式)都是相同的,即表示內(nèi)存地址的十六進(jìn)制數(shù)字,不同數(shù)據(jù)類型的指針之間的唯一區(qū)別是指針指向的變量或常量的數(shù)據(jù)類型。
當(dāng)我們非常頻繁地使用指針時(shí),很少有重要的操作。
這是通過使用一元運(yùn)算符 * 完成的,該運(yùn)算符返回位于變量操作數(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分配給指針變量,這是在變量聲明時(shí)完成的,分配為null的指針稱為 null 指針。
空指針是在幾個(gè)標(biāo)準(zhǔn)庫(包括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)存,因?yàn)樵搩?nèi)存是由操作系統(tǒng)保留的,然而;存儲(chǔ)器地址0具有特殊的意義;它指示指針不旨在指向可訪問的存儲(chǔ)位置。
按照慣示例,如果指針包含空(零)值,則假定該指針不指向任何內(nèi)容。要檢查空指針,可以使用以下if語句-
if(ptr) //succeeds if p is not null
if(!ptr) //succeeds if p is null
因此,如果為所有未使用的指針賦予了空值,并且避免了使用空指針,則可以避免意外誤用未初始化的指針。
可以在指針上使用四種算術(shù)運(yùn)算符:++,--,+和-
為了理解指針?biāo)阈g(shù),讓我們考慮一個(gè)名為 ptr 的整數(shù)指針,該指針指向地址1000。假設(shè)32位整數(shù),讓我們對(duì)指針執(zhí)行以下算術(shù)運(yùn)算-
ptr++
那么 ptr 將指向位置1004,因?yàn)槊看蝡tr遞增時(shí),它都指向下一個(gè)整數(shù)。該操作會(huì)將指針移動(dòng)到下一個(gè)存儲(chǔ)位置,而不會(huì)影響該存儲(chǔ)位置的實(shí)際值。
如果 ptr 指向地址為1000的字符,則上述操作將指向位置1001,因?yàn)橄乱粋€(gè)字符將在1001處可用。
我們更喜歡在程序中使用指針而不是數(shù)組,因?yàn)樽兞恐羔樋梢赃f增,這與數(shù)組名不同,因?yàn)閿?shù)組名是常量指針,因此不能遞增。以下程序遞增變量指針以訪問數(shù)組的每個(gè)后續(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]設(shè)置第二個(gè)元素,而ptr [0]用來設(shè)置第零個(gè)元素,增量運(yùn)算符可以與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
指向指針的指針是多種間接形式或指針鏈的形式。通常,指針包含變量的地址,當(dāng)我們定義一個(gè)指向指針的指針時(shí),第一個(gè)指針包含第二個(gè)指針的地址,該地址指向包含實(shí)際值的位置,如下所示。
作為指針的指針的變量必須這樣聲明。這是通過在其名稱前面放置一個(gè)額外的星號(hào)*來完成的。如以下是聲明指向int類型指針的語法-
int **var;
當(dāng)指向指針的指針間接指向目標(biāo)值時(shí),訪問該值需要兩次應(yīng)用星號(hào)**運(yùn)算符,如下面的示例所示-
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ù)聲明為指針類型。
下面的簡(jiǎn)單示例將指針傳遞給函數(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個(gè)數(shù)字,表示第一個(gè)數(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ù)組第一個(gè)元素的常量指針。因此,在聲明中-
double balance[50];
balance是指向&balance [0]的指針,它是數(shù)組balance的第一個(gè)元素的地址。因此,以下程序片段為p分配了balance的第一個(gè)元素的地址-
double *p;
double balance[10];
p=balance;
將數(shù)組名稱用作常量指針是合法的,反之亦然。因此,*(balance + 4)是訪問balance [4]數(shù)據(jù)的合法方法。
一旦將第一個(gè)元素的地址存儲(chǔ)在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
更多建議: