什么是指針?
其實指針就像是其它變量一樣,所不同的是一般的變量包含的是實際的真實的數(shù)據(jù),而指針是一個指示器,它告訴程序在內(nèi)存的哪塊區(qū)域可以找到數(shù)據(jù)。這是一個非常重要的概念,有很多程序和算法都是圍繞指針而設(shè)計的,如鏈表。
開始學(xué)習(xí)
如何定義一個指針呢?就像你定義一個其它變量一樣,只不過你要在指針名字前加上一個星號。我們來看一個例子:下面這個程序定義了兩個指針,它們都是指向整型數(shù)據(jù)。
int* pNumberOne;
int* pNumberTwo;
你注意到在兩個變量名前的“p”前綴了嗎?這是程序員通常在定義指針時的
一個習(xí)慣,以提高便程序的閱讀性,表示這是個指針?,F(xiàn)在讓我們來初始化這兩個指針:
pNumberOne = &some_number;
pNumberTwo = &some_other_number;
&號讀作“什么的地址”,它表示返回的是變量在內(nèi)存中的地址而不是變量本身的值。在這個例子中,pNumberOne 等于some_number的地址,所以現(xiàn)在pNumberOne指向some_number。 如果現(xiàn)在我們在程序中要用到some_number,我們就可以使用pNumberOne。
我們來學(xué)習(xí)一個例子:
在這個例子中你將學(xué)到很多,如果你對指針的概念一點都不了解,我建議你多看幾遍這個例子,指針是個很復(fù)雜的東西,但你會很快掌握它的。
這個例子用以增強你對上面所介紹內(nèi)容的了解。它是用C編寫的(注:原英文版是用C寫的代碼,譯者重新用C++改寫寫了所有代碼,并在DEV C++ 和VC++中編譯通過!)
#include
void main()
{
// 聲明變量:
int nNumber;
int *pPointer;
// 現(xiàn)在給它們賦值:
nNumber = 15;
pPointer = &nNumber;
//打印出變量nNumber的值:
cout<<"nNumber is equal to :"<< nNumber< // 現(xiàn)在通過指針改變nNumber的值:
*pPointer = 25;
//證明nNumber已經(jīng)被上面的程序改變
//重新打印出nNumber的值:
cout<<"nNumber is equal to :"< }
通讀一下這個程序,編譯并運行它,務(wù)必明白它是怎樣工作的。如果你完成了,準(zhǔn)備好,開始下一小節(jié)。
陷井!
試一下,你能找出下面這段程序的錯誤嗎?
#include
int *pPointer;
void SomeFunction();
{
int nNumber;
nNumber = 25;
//讓指針指向nNumber:
pPointer = &nNumber;
}
void main()
{
SomeFunction(); //為pPointer賦值
//為什么這里失敗了?為什么沒有得到25
cout<<"Value of *pPointer: "<<*pPointer< }
這段程序先調(diào)用了SomeFunction函數(shù),創(chuàng)建了個叫nNumber的變量,接著讓指針pPointer指向了它??墒菃栴}出在哪兒呢?當(dāng)函數(shù)結(jié)束后,nNumber被刪掉了,
因為這一個局部變量。局部變量在定義它的函數(shù)執(zhí)行完后都會被系統(tǒng)自動刪掉。也就是說當(dāng)Somefunction..函數(shù)返回主函數(shù)main()時,這個變量已經(jīng)被刪掉,但pPointer還指著變量曾經(jīng)用過的但現(xiàn)在已不屬于這個程序的區(qū)域。如果你還不明白,你可以再讀讀這個程序,注意它的局部變量和全局變量,這些概念都非常重要。
但這個問題怎么解決呢?答案是動態(tài)分配技術(shù)。注意這在C和C++中是不同的。由于大多數(shù)程序員都是用C++,所以我用到的是C++中常用的稱謂。
動態(tài)分配
動態(tài)分配是指針的關(guān)鍵技術(shù)。它是用來在不必定義變量的情況下分配內(nèi)存和讓指針去指向它們。盡管這么說可能會讓你迷惑,其實它真的很簡單。下面的代碼就是一個為一個整型數(shù)據(jù)分配內(nèi)存的例子:
int *pNumber;
pNumber = new int;
第一行聲明一個指針pNumber。第二行為一個整型數(shù)據(jù)分配一個內(nèi)存空間,并讓pNumber指向這個新內(nèi)存空間。下面是一個新例,這一次是用double雙精型:
double *pDouble;
pDouble = new double;
這種格式是一個規(guī)則,這樣寫你是不會錯的。
但動態(tài)分配又和前面的例子有什么不同呢?就是在函數(shù)返回或執(zhí)行完畢時,你分配的這塊內(nèi)存區(qū)域是不會被刪除的所以我們現(xiàn)在可以用動態(tài)分配重寫上面的程序:
#include
int *pPointer;
void SomeFunction()
{
// 讓指針指向一個新的整型
pPointer = new int;
*pPointer = 25;
}
void main()
{
SomeFunction(); // 為pPointer賦值
cout<<"Value of *pPointer: "<<*pPointer< }
通讀這個程序,編譯并運行它,務(wù)必理解它是怎樣工作的。當(dāng)SomeFunction調(diào)用時,它分配了一個內(nèi)存,并讓pPointer指向它。這一次,當(dāng)函數(shù)返回時,新的內(nèi)存區(qū)域被保留下來,所以pPointer始終指著有用的信息,這是因為了動態(tài)分配。但是你再仔細(xì)讀讀上面這個程序,雖然它得到了正確結(jié)果,可仍有一個嚴(yán)重的錯誤。
delete pPointer;
這樣就差不多了,你不得不小心。在這你終止了一個有效的指針(一個確實指向某個內(nèi)存的指針)。下面的程序,它不會浪費任何的內(nèi)存:
#include
調(diào)用時,它分配了一個內(nèi)存,并讓pPointer指向它。這一次,當(dāng)函數(shù)返回時,新的內(nèi)存區(qū)域被保留下來,所以pPointer始終指著有用的信息,這是因為了動態(tài)分配。但是你再仔細(xì)讀讀上面這個程序,雖然它得到了正確結(jié)果,可仍有一個嚴(yán)重的錯誤。
分配了內(nèi)存,別忘了回收
太復(fù)雜了,怎么會還有嚴(yán)重的錯誤!其實要改正并不難。問題是:你動態(tài)地分配了一個內(nèi)存空間,可它絕不會被自動刪除。也就是說,這塊內(nèi)存空間會一直存在,直到你告訴電腦你已經(jīng)使用完了??山Y(jié)果是,你并沒有告訴電腦你已不再需要這塊內(nèi)存空間了,所以它會繼續(xù)占據(jù)著內(nèi)存空間造成浪費,甚至你的程序運行完畢,其它程序運行時它還存在。當(dāng)這樣的問題積累到一定程度,最終將導(dǎo)致系統(tǒng)崩潰。所以這是很重要的,在你用完它以后,請釋放它的空間,如:delete pPointer;
這樣就差不多了,你不得不小心。在這你終止了一個有效的指針(一個確實指向某個內(nèi)存的指針)。
下面的程序,考試大提示它不會浪費任何的內(nèi)存:
#include
int *pPointer;
void SomeFunction()
{
// 讓指針指向一個新的整型
pPointer = new int;
*pPointer = 25;
}
void main()
{
SomeFunction(); //為pPointer賦值
cout<<"Value of *pPointer: "<<*pPointer< delete pPointer;
}
只有一行與前一個程序不同,但就是這最后一行十分地重要。如果你不刪除它,你就會制造一起“內(nèi)存漏洞”,而讓內(nèi)存逐漸地泄漏。(譯者:假如在程序中調(diào)用了兩次SomeFunction,你又該如何修改這個程序呢?考試大提示請讀者自己思考)
傳遞指針到函數(shù)
傳遞指針到函數(shù)是非常有用的,也很容易掌握。如果我們寫一個程序,讓一個數(shù)加上5,看一看這個程序完整嗎?:
#include
void AddFive(int Number)
{
Number = Number + 5;
}
void main()
{
int nMyNumber = 18;
cout<<"My original number is "< AddFive(nMyNumber);
cout<<"My new number is "< //得到了結(jié)果23嗎?問題出在哪兒?
}
問題出在函數(shù)AddFive里用到的Number是變量nMyNumber的一個副本而傳遞給函數(shù),而不是變量本身。因此, " Number = Number + 5" 這一行是把變量的副本加了5,而原始的變量在主函數(shù)main()里依然沒變。試著運行這個程序,自己去體會一下。要解決這個問題,我們就要傳遞一個指針到函數(shù),所以我們要修改一下函數(shù)讓它能接受指針:把’void AddFive(int Number)’ 改成 ’void AddFive(int*Number)’ 。下面就是改過的程序,注意函數(shù)調(diào)用時要用&號,以表示傳遞的是指針:
#include
void AddFive(int* Number)
{
*Number = *Number + 5;
}
void main()
{
int nMyNumber = 18;
}
其實指針就像是其它變量一樣,所不同的是一般的變量包含的是實際的真實的數(shù)據(jù),而指針是一個指示器,它告訴程序在內(nèi)存的哪塊區(qū)域可以找到數(shù)據(jù)。這是一個非常重要的概念,有很多程序和算法都是圍繞指針而設(shè)計的,如鏈表。
開始學(xué)習(xí)
如何定義一個指針呢?就像你定義一個其它變量一樣,只不過你要在指針名字前加上一個星號。我們來看一個例子:下面這個程序定義了兩個指針,它們都是指向整型數(shù)據(jù)。
int* pNumberOne;
int* pNumberTwo;
你注意到在兩個變量名前的“p”前綴了嗎?這是程序員通常在定義指針時的
一個習(xí)慣,以提高便程序的閱讀性,表示這是個指針?,F(xiàn)在讓我們來初始化這兩個指針:
pNumberOne = &some_number;
pNumberTwo = &some_other_number;
&號讀作“什么的地址”,它表示返回的是變量在內(nèi)存中的地址而不是變量本身的值。在這個例子中,pNumberOne 等于some_number的地址,所以現(xiàn)在pNumberOne指向some_number。 如果現(xiàn)在我們在程序中要用到some_number,我們就可以使用pNumberOne。
我們來學(xué)習(xí)一個例子:
在這個例子中你將學(xué)到很多,如果你對指針的概念一點都不了解,我建議你多看幾遍這個例子,指針是個很復(fù)雜的東西,但你會很快掌握它的。
這個例子用以增強你對上面所介紹內(nèi)容的了解。它是用C編寫的(注:原英文版是用C寫的代碼,譯者重新用C++改寫寫了所有代碼,并在DEV C++ 和VC++中編譯通過!)
#include
void main()
{
// 聲明變量:
int nNumber;
int *pPointer;
// 現(xiàn)在給它們賦值:
nNumber = 15;
pPointer = &nNumber;
//打印出變量nNumber的值:
cout<<"nNumber is equal to :"<< nNumber<
*pPointer = 25;
//證明nNumber已經(jīng)被上面的程序改變
//重新打印出nNumber的值:
cout<<"nNumber is equal to :"<
通讀一下這個程序,編譯并運行它,務(wù)必明白它是怎樣工作的。如果你完成了,準(zhǔn)備好,開始下一小節(jié)。
陷井!
試一下,你能找出下面這段程序的錯誤嗎?
#include
int *pPointer;
void SomeFunction();
{
int nNumber;
nNumber = 25;
//讓指針指向nNumber:
pPointer = &nNumber;
}
void main()
{
SomeFunction(); //為pPointer賦值
//為什么這里失敗了?為什么沒有得到25
cout<<"Value of *pPointer: "<<*pPointer<
這段程序先調(diào)用了SomeFunction函數(shù),創(chuàng)建了個叫nNumber的變量,接著讓指針pPointer指向了它??墒菃栴}出在哪兒呢?當(dāng)函數(shù)結(jié)束后,nNumber被刪掉了,
因為這一個局部變量。局部變量在定義它的函數(shù)執(zhí)行完后都會被系統(tǒng)自動刪掉。也就是說當(dāng)Somefunction..函數(shù)返回主函數(shù)main()時,這個變量已經(jīng)被刪掉,但pPointer還指著變量曾經(jīng)用過的但現(xiàn)在已不屬于這個程序的區(qū)域。如果你還不明白,你可以再讀讀這個程序,注意它的局部變量和全局變量,這些概念都非常重要。
但這個問題怎么解決呢?答案是動態(tài)分配技術(shù)。注意這在C和C++中是不同的。由于大多數(shù)程序員都是用C++,所以我用到的是C++中常用的稱謂。
動態(tài)分配
動態(tài)分配是指針的關(guān)鍵技術(shù)。它是用來在不必定義變量的情況下分配內(nèi)存和讓指針去指向它們。盡管這么說可能會讓你迷惑,其實它真的很簡單。下面的代碼就是一個為一個整型數(shù)據(jù)分配內(nèi)存的例子:
int *pNumber;
pNumber = new int;
第一行聲明一個指針pNumber。第二行為一個整型數(shù)據(jù)分配一個內(nèi)存空間,并讓pNumber指向這個新內(nèi)存空間。下面是一個新例,這一次是用double雙精型:
double *pDouble;
pDouble = new double;
這種格式是一個規(guī)則,這樣寫你是不會錯的。
但動態(tài)分配又和前面的例子有什么不同呢?就是在函數(shù)返回或執(zhí)行完畢時,你分配的這塊內(nèi)存區(qū)域是不會被刪除的所以我們現(xiàn)在可以用動態(tài)分配重寫上面的程序:
#include
int *pPointer;
void SomeFunction()
{
// 讓指針指向一個新的整型
pPointer = new int;
*pPointer = 25;
}
void main()
{
SomeFunction(); // 為pPointer賦值
cout<<"Value of *pPointer: "<<*pPointer<
通讀這個程序,編譯并運行它,務(wù)必理解它是怎樣工作的。當(dāng)SomeFunction調(diào)用時,它分配了一個內(nèi)存,并讓pPointer指向它。這一次,當(dāng)函數(shù)返回時,新的內(nèi)存區(qū)域被保留下來,所以pPointer始終指著有用的信息,這是因為了動態(tài)分配。但是你再仔細(xì)讀讀上面這個程序,雖然它得到了正確結(jié)果,可仍有一個嚴(yán)重的錯誤。
delete pPointer;
這樣就差不多了,你不得不小心。在這你終止了一個有效的指針(一個確實指向某個內(nèi)存的指針)。下面的程序,它不會浪費任何的內(nèi)存:
#include
調(diào)用時,它分配了一個內(nèi)存,并讓pPointer指向它。這一次,當(dāng)函數(shù)返回時,新的內(nèi)存區(qū)域被保留下來,所以pPointer始終指著有用的信息,這是因為了動態(tài)分配。但是你再仔細(xì)讀讀上面這個程序,雖然它得到了正確結(jié)果,可仍有一個嚴(yán)重的錯誤。
分配了內(nèi)存,別忘了回收
太復(fù)雜了,怎么會還有嚴(yán)重的錯誤!其實要改正并不難。問題是:你動態(tài)地分配了一個內(nèi)存空間,可它絕不會被自動刪除。也就是說,這塊內(nèi)存空間會一直存在,直到你告訴電腦你已經(jīng)使用完了??山Y(jié)果是,你并沒有告訴電腦你已不再需要這塊內(nèi)存空間了,所以它會繼續(xù)占據(jù)著內(nèi)存空間造成浪費,甚至你的程序運行完畢,其它程序運行時它還存在。當(dāng)這樣的問題積累到一定程度,最終將導(dǎo)致系統(tǒng)崩潰。所以這是很重要的,在你用完它以后,請釋放它的空間,如:delete pPointer;
這樣就差不多了,你不得不小心。在這你終止了一個有效的指針(一個確實指向某個內(nèi)存的指針)。
下面的程序,考試大提示它不會浪費任何的內(nèi)存:
#include
int *pPointer;
void SomeFunction()
{
// 讓指針指向一個新的整型
pPointer = new int;
*pPointer = 25;
}
void main()
{
SomeFunction(); //為pPointer賦值
cout<<"Value of *pPointer: "<<*pPointer<
}
只有一行與前一個程序不同,但就是這最后一行十分地重要。如果你不刪除它,你就會制造一起“內(nèi)存漏洞”,而讓內(nèi)存逐漸地泄漏。(譯者:假如在程序中調(diào)用了兩次SomeFunction,你又該如何修改這個程序呢?考試大提示請讀者自己思考)
傳遞指針到函數(shù)
傳遞指針到函數(shù)是非常有用的,也很容易掌握。如果我們寫一個程序,讓一個數(shù)加上5,看一看這個程序完整嗎?:
#include
void AddFive(int Number)
{
Number = Number + 5;
}
void main()
{
int nMyNumber = 18;
cout<<"My original number is "<
cout<<"My new number is "<
}
問題出在函數(shù)AddFive里用到的Number是變量nMyNumber的一個副本而傳遞給函數(shù),而不是變量本身。因此, " Number = Number + 5" 這一行是把變量的副本加了5,而原始的變量在主函數(shù)main()里依然沒變。試著運行這個程序,自己去體會一下。要解決這個問題,我們就要傳遞一個指針到函數(shù),所以我們要修改一下函數(shù)讓它能接受指針:把’void AddFive(int Number)’ 改成 ’void AddFive(int*Number)’ 。下面就是改過的程序,注意函數(shù)調(diào)用時要用&號,以表示傳遞的是指針:
#include
void AddFive(int* Number)
{
*Number = *Number + 5;
}
void main()
{
int nMyNumber = 18;
}