最近因工做要求要來學習C++了,在這裏作一下學習的記錄程序員
對於C語言而言,最重要的就是指針了,它是C語言的特點也是難點之一,固然,做爲繼承者C++也是如此編程
指針數組
int * p_updates;
這代表,* p_updates的類型爲int。因爲*運算符被用於指針,所以p_updates變量自己必須是指針。咱們說p_updates指向int類型,咱們還說p_updates的類型是指向int的指針,或int*。能夠這樣說,p_updates是指針(地址),而*p_updates是int,而不是指針.安全
指針的危險函數
危險更易發生在那些使用指針不仔細的人身上。極其重要的一點是:在C++中建立指針時,計算機將分配用來存儲地址的內存,但不會分配用來存儲指針所指向的數據的內存。爲數據提供空間是一個獨立的步驟,忽略這一步無疑是自找麻煩.學習
long * fellow; *fellow = 223323;
fellow確實是一個指針,但它指向哪裏呢?上述代碼沒有將地址賦給fellow。那麼223323將被放在哪裏呢?咱們不知道。因爲fellow沒有被初始化,它可能有任何值。無論值是什麼,程序都將它解釋爲存儲223323的地址。若是fellow的值碰巧爲1200,計算機將把數據放在地址1200上,即便這恰巧是程序代碼的地址。fellow指向的地方極可能並非所要存儲223323的地方。這種錯誤可能會致使一些最隱匿、最難以跟蹤的bug。this
指針和數字spa
指針不是整型,雖然計算機一般把地址看成整數來處理。從概念上看,指針與整數是大相徑庭的類型。整數是能夠執行加、減、除等運算的數字,而指針描述的是位置,將兩個地址相乘沒有任何意義。從能夠對整數和指針執行的操做上看,它們也是彼此不一樣的。所以,不能簡單地將整數賦給指針:指針
int *pt; pt = 0xB8000000; //type mismatch
在這裏,左邊是指向int的指針,所以能夠把它賦給地址,但右邊是一個整數。您可能知道,0xB8000000是老式計算機系統中視頻內存的組合段偏移地址,但這條語句並無告訴程序,這個數字就是一個地址。在C99標準發佈以前,C語言容許這樣賦值。但C++在類型一致方面的要求更嚴格,編譯器將顯示一條錯誤消息,通告類型不匹配。要將數字值做爲地址來使用,應經過強制類型轉換將數字轉換爲適當的地址類型:code
int *pt; pt = (int *)0xB8000000;
這樣,賦值語句的兩邊都是整數的地址,所以這樣賦值有效。注意,pt是int值的地址並不意味着pt自己的類型是int。例如,在有些平臺中,int類型是個2字節值,而地址是個4字節值。
使用new來分配內存
對指針的工做方式有必定了解後,來看看它如何實如今程序運行時分配內存。前面咱們都將指針初始化爲變量的地址;變量是在編譯時分配的有名稱的內存,而指針只是爲能夠經過名稱直接訪問的內存提供了一個別名。指針真正的用武之地在於,在運行階段分配未命名的內存以存儲值。在這種狀況下,只能經過指針來訪問內存。在C語言中,能夠用庫函數malloc( )來分配內存;在C++中仍然能夠這樣作,但C++還有更好的方法—new運算符。
下面來試試這種新技術,在運行階段爲一個int值分配未命名的內存,並使用指針來訪問這個值。這裏的關鍵所在是C++的new運算符。程序員要告訴new,須要爲哪一種數據類型分配內存;new將找到一個長度正確的內存塊,並返回該內存塊的地址。程序員的責任是將該地址賦給一個指針。下面是一個這樣的示例:
int * pn = new int;
new int告訴程序,須要適合存儲int的內存。new運算符根據類型來肯定須要多少字節的內存。而後,它找到這樣的內存,並返回其地址。接下來,將地址賦給pn,pn是被聲明爲指向int的指針。如今,pn是地址,而*pn是存儲在那裏的值。將這種方法與將變量的地址賦給指針進行比較:
int higgens; int *pt = &higgens;
在這兩種狀況(pn和pt)下,都是將一個int變量的地址賦給了指針。在第二種狀況下,能夠經過名稱higgens來訪問該int,在第一種狀況下,則只能經過該指針進行訪問。這引出了一個問題:pn指向的內存沒有名稱,如何稱呼它呢?咱們說pn指向一個數據對象,這裏的「對象」不是「面向對象編程」中的對象,而是同樣「東西」。術語「數據對象」比「變量」更通用,它指的是爲數據項分配的內存塊。所以,變量也是數據對象,但pn指向的內存不是變量。乍一看,處理數據對象的指針方法可能不太好用,但它使程序在管理內存方面有更大的控制權。
爲一個數據對象(能夠是結構,也能夠是基本類型)得到並指定分配內存的通用格式以下:
typeName * pointer_name = new typeName;(如: double * p = new double)
使用delete釋放內存
當須要內存時,可使用new來請求,這只是C++內存管理數據包中有魅力的一個方面。另外一個方面是delete運算符,它使得在使用完內存後,可以將其歸還給內存池,這是通向最有效地使用內存的關鍵一步。歸還或釋放(free)的內存可供程序的其餘部分使用。使用delete時,後面要加上指向內存塊的指針(這些內存塊最初是用new分配的):
int *ps = new int; delete ps;
這將釋放ps指向的內存,但不會刪除指針ps自己。例如,能夠將ps從新指向另外一個新分配的內存塊。必定要配對地使用new和delete;不然將發生內存泄漏(memory leak),也就是說,被分配的內存再也沒法使用了。若是內存泄漏嚴重,則程序將因爲不斷尋找更多內存而終止。
不要嘗試釋放已經釋放的內存塊,C++標準指出,這樣作的結果將是不肯定的,這意味着什麼狀況均可能發生。
另外,不能使用delete來釋放聲明變量所得到的內存,以下:
int jugs = 5; int *pi = &jugs; delete pi; //錯誤..內存不是經過new來進行分配的
意思就是 new delete是要同對出現的。
使用delete的關鍵在於,將它用於new分配的內存。這並不意味着要用於new的指針,而是用於new的地址
int *ps = new int; int *pq = ps; delete pq;
通常來講,不要建立兩個指向同一個內存塊的指針,由於這將增長錯誤地刪除同一個內存塊兩次的可能性。但稍後您會看到,對於返回指針的函數,使用另外一個指針確實有道理。
使用new來建立動態數組
若是程序只須要一個值,則可能會聲明一個簡單變量,由於對於管理一個小型數據對象來講,這樣作比使用new和指針更簡單,儘管給人留下的印象不那麼深入。一般,對於大型數據(如數組、字符串和結構),應使用new,這正是new的用武之地。例如,假設要編寫一個程序,它是否須要數組取決於運行時用戶提供的信息。若是經過聲明來建立數組,則在程序被編譯時將爲它分配內存空間。無論程序最終是否使用數組,數組都在那裏,它佔用了內存。在編譯時給數組分配內存被稱爲靜態聯編(static binding),意味着數組是在編譯時加入到程序中的。但使用new時,若是在運行階段須要數組,則建立它;若是不須要,則不建立。還能夠在程序運行時選擇數組的長度。這被稱爲動態聯編(dynamic binding),意味着數組是在程序運行時建立的。這種數組叫做動態數組(dynamic array)。使用靜態聯編時,必須在編寫程序時指定數組的長度;使用動態聯編時,程序將在運行時肯定數組的長度。
在C++中,建立動態數組很容易;只要將數組的元素類型和元素數目告訴new便可。必須在類型名後加上方括號,其中包含元素數目。例如,要建立一個包含10個int元素的數組,能夠這樣作:
int *psome = new int[10];
new運算符返回第一個元素的地址。在這個例子中,該地址被賦給指針psome。
當程序使用完new分配的內存塊時,應使用delete釋放它們。然而,對於使用new建立的數組,應使用另外一種格式的delete來釋放:
delete [] psome;
方括號告訴程序,應釋放整個數組,而不只僅是指針指向的元素。請注意delete和指針之間的方括號。若是使用new時,不帶方括號,則使用delete時,也不該帶方括號。若是使用new時帶方括號,則使用delete時也應帶方括號。C++的早期版本沒法識別方括號表示法。然而,對於ANSI/ISO標準來講,new與delete的格式不匹配致使的後果是不肯定的,這意味着程序員不能依賴於某種特定的行爲。下面是一個例子:
int * pt = new int; short * ps = new short[500]; delete [] pt; //effect is undefined, don't do this delete ps; //effect is undefined, don't do this
總之,使用new和delete時,應遵照如下規則。
下面的語句建立指針psome,它指向包含10個int值的內存塊中的第1個元素:
int * p = new int[10];
能夠將它看做是一根指向該元素的手指。假設int佔4個字節,則將手指沿正確的方向移動4個字節,手指將指向第2個元素。總共有10個元素,這就是手指的移動範圍。所以,new語句提供了識別內存塊中每一個元素所需的所有信息。
如今從實際角度考慮這個問題。如何訪問其中的元素呢?第一個元素不成問題。因爲psome指向數組的第1個元素,所以*psome是第1個元素的值。這樣,還有9個元素。若是沒有使用過C語言,下面這種最簡單的方法可能會令您大吃一驚:只要把指針看成數組名使用便可。也就是說,對於第1個元素,可使用psome[0],而不是*psome;對於第2個元素,可使用psome[1],依此類推。這樣,使用指針來訪問動態數組就很是簡單了,雖然還不知道爲什麼這種方法管用。能夠這樣作的緣由是,C和C++內部都使用指針來處理數組。數組和指針基本等價是C和C++的優勢之一(這在有時候也是個問題,但這是另外一碼事)。稍後將更詳細地介紹這種等同性
int main() { double* p3 = new double[3]; p3[0] = 0.2; p3[1] = 0.5; p3[2] = 0.8; cout << "p3[1] is " << p3[1] << endl; p3 = p3 + 1; cout << "now p3[0] is " << p3[0] << endl; cout << "p3[1] is " << p3[1] << endl; p3 = p3 - 1; delete[] p3; return 0; }
下面是該程序的輸出:
p3[1] is 0.5 now p3[0] is 0.5 p3[1] is 0.8
從中可知,指針p3看成數組名來使用,p3[0]爲第1個元素,依次類推。下面的代碼行指出了數組名和指針之間的根本差異:
p3 = p3+1;
不能修改數組名的值。但指針是變量,所以能夠修改它的值。請注意將p3加1的效果。表達式p3[0]如今指的是數組的第2個值。所以,將p3加1致使它指向第2個元素而不是第1個。將它減1後,指針將指向原來的值,這樣程序即可以給delete[ ]提供正確的地址。
相鄰的int地址一般相差2個字節或4個字節,而將p3加1後,它將指向下一個元素的地址,這代表指針算術有一些特別的地方。狀況確實如此。
指針、數組和指針算術
指針和數組基本等價的緣由在於指針算術(pointer arithmetic)和C++內部處理數組的方式。首先,咱們來看一看算術。將整數變量加1後,其值將增長1;但將指針變量加1後,增長的量等於它指向的類型的字節數。將指向double的指針加1後,若是系統對double使用8個字節存儲,則數值將增長8;將指向short的指針加1後,若是系統對short使用2個字節存儲,則指針值將增長2。如下程序演示了這種使人吃驚的現象,它還說明了另外一點:C++將數組名解釋爲地址。
int main() { double wages[3] = { 10000.0,20000.0,30000.0 }; short stacks[3] = { 3,2,1 }; //獲取數組地址的兩種方式 double* pw = wages; //數組名即爲地址 short* ps = &stacks[0]; cout << "pw= " << pw << ", *pw = " << *pw << endl; pw = pw + 1; cout << "pw指針加1:\n"; cout << "pw= " << pw << ", *pw = " << *pw << endl; cout << endl; cout << "ps= " << ps << ", *ps = " << *ps << endl; ps = ps + 1; cout << "ps指針加1:\n"; cout << "ps= " << ps << ", *ps = " << *ps << endl; cout << endl; cout << "使用數組表示法訪問兩個元素" << endl; cout << "stack[0] = " << stacks[0] << ", stack[1] = " << stacks[1] << endl; cout << "使用指針表示法訪問兩個元素" << endl; cout << "*stack = " << *stacks << ", *(stack+1) = " << *(stacks+1) << endl; cout << "wages數組的大小爲:" << sizeof(wages) << endl; cout << "pw指針的大小爲:" << sizeof(pw) << endl; }
下面是該程序的輸出:
pw= 00EFFE80, *pw = 10000 pw指針加1: pw= 00EFFE88, *pw = 20000 ps= 00EFFE70, *ps = 3 ps指針加1: ps= 00EFFE72, *ps = 2 使用數組表示法訪問兩個元素 stack[0] = 3, stack[1] = 2 使用指針表示法訪問兩個元素 *stack = 3, *(stack+1) = 2 wages數組的大小爲:24 pw指針的大小爲:4
在多數狀況下,C++將數組名解釋爲數組第1個元素的地址。所以,下面的語句將pw聲明爲指向double類型的指針,而後將它初始化爲wages—wages數組中第1個元素的地址:
double * pw =wages; //和全部數組同樣,wages也存在下面的等式 wages = &wages[0] = 數組第一個元素的地址
爲代表狀況確實如此,該程序在表達式&stacks[0]中顯式地使用地址運算符來將ps指針初始化爲stacks數組的第1個元素。
接下來,程序查看pw和*pw的值。前者是地址,後者是存儲在該地址中的值。因爲pw指向第1個元素,所以*pw顯示的值爲第1個元素的值,即10000。接着,程序將pw加1。正如前面指出的,這樣數字地址值將增長8,這使得pw的值爲第2個元素的地址。所以,*pw如今的值是20000—第2個元素的值(參見下圖,爲使改圖更爲清晰,對其中的地址值作了調整)。
此後,程序對ps執行相同的操做。這一次因爲ps指向的是shor t類型,而short佔用2個字節,所以將指針加1時,其值將增長2。結果是,指針也指向數組中下一個元素。
如今來看一看數組表達式stacks[1]。C++編譯器將該表達式看做是*(stacks + 1),這意味着先計算數組第2個元素的地址,而後找到存儲在那裏的值。最後的結果即是stacks [1]的含義(運算符優先級要求使用括號,若是不使用括號,將給*stacks加1,而不是給stacks加1)。
不少狀況下,能夠相同的方式使用指針名和數組名。對於它們,可使用數組方括號表示法,也可使用解除引用運算符(*)。在多數表達式中,它們都表示地址。區別之一是,能夠修改指針的值,而數組名是常量。
數組的地址
對數組取地址時,數組名也不會被解釋爲其地址。等等,數組名難道不被解釋爲數組的地址嗎?不徹底如此:數組名被解釋爲其第一個元素的地址,而對數組名應用地址運算符時,獲得的是整個數組的地址:
short tell[10]; cout << tell << endl; //顯示 &tell[0]; cout << &tell << endl; //顯示整個數組的地址
從數字上說,這兩個地址相同;但從概念上說,&tell[0](即tell)是一個2字節內存塊的地址,而&tell是一個20字節內存塊的地址。所以,表達式tell + 1將地址值加2,而表達式&tell + 2將地址加20。換句話說,tell是一個short指針(* short),而&tell是一個這樣的指針,即指向包含20個元素的short數組(short (*) [20])。
您可能會問,前面有關&tell的類型描述是如何來的呢?首先,您能夠這樣聲明和初始化這種指針:
short (*pas)[20] = &tell
若是省略括號,優先級規則將使得pas先與[20]結合,致使pas是一個short指針數組,它包含20個元素,所以括號是必不可少的。其次,若是要描述變量的類型,可將聲明中的變量名刪除。所以,pas的類型爲short (*) [20]。另外,因爲pas被設置爲&tell,所以*pas與tell等價,因此(*pas) [0]爲tell數組的第一個元素。
總之,使用new來建立數組以及使用指針來訪問不一樣的元素很簡單。只要把指針看成數組名對待便可。然而,要理解爲什麼能夠這樣作,將是一種挑戰。要想真正瞭解數組和指針,應認真複習它們的相互關係。
總結
1.聲明指針
要聲明指向特定類型的指針,請使用下面的格式:
typeName * pointerName //實例 double * pn; char *pc;
其中,pn和pc都是指針,而double *和char *是指向double的指針和指向char的指針。
2.給指針賦值
應將內存地址賦給指針。能夠對變量名應用&運算符,來得到被命名的內存的地址,new運算符返回未命名的內存的地址。
double *pn; double *pa; char *pc; double bubble = 3.2; pn = &bubble; pc = new char; pa = new double[30];
3.對指針解除引用
對指針解除引用意味着得到指針指向的值。對指針應用解除引用或間接值運算符(*)來解除引用。所以,若是像上面的例子中那樣,pn是指向bubble的指針,則*pn是指向的值,即3.2。
cout<< *pn; *pc='S'
另外一種對指針解除引用的方法是使用數組表示法,例如,pn[0]與*pn是同樣的。決不要對未被初始化爲適當地址的指針解除引用。
4.區分指針和指針所指向的值
若是pt是指向int的指針,則*pt不是指向int的指針,而是徹底等同於一個int類型的變量。pt纔是指針。
int *pt = new int; *pt =5;
5.數組名
在多數狀況下,C++將數組名視爲數組的第一個元素的地址。
int tacos[10];
一種例外狀況是,將sizeof運算符用於數組名用時,此時將返回整個數組的長度(單位爲字節)。
6.指針算術
C++容許將指針和整數相加。加1的結果等於原來的地址值加上指向的對象佔用的總字節數。還能夠將一個指針減去另外一個指針,得到兩個指針的差。後一種運算將獲得一個整數,僅當兩個指針指向同一個數組(也能夠指向超出結尾的一個位置)時,這種運算纔有意義;這將獲得兩個元素的間隔。
int main() { int tacos[10] = {5,2,8,4,1,2,2,4,6,8}; int* pt = tacos; //假設tacos的起始地址爲3000 pt = pt + 1; //若是int佔4字節,此時就是pt = 3004 int* pe = &tacos[9]; //pe爲3036 pe = pe - 1; //pe爲3032 int diff = pe - pt; //diff = 7,tacos[8]與tacos[1]的間隔 cout << pt << endl; cout << pe << endl; cout << diff << endl; }
7.數組的動態聯編和靜態聯編
使用數組聲明來建立數組時,將採用靜態聯編,即數組的長度在編譯時設置:
int tacos[10];
使用new[ ]運算符建立數組時,將採用動態聯編(動態數組),即將在運行時爲數組分配空間,其長度也將在運行時設置。使用完這種數組後,應使用delete [ ]釋放其佔用的內存:
int * pz = new int[10]; delete [] pz;
8.數組表示法和指針表示法
使用方括號數組表示法等同於對指針解除引用:
tacos[0]=*tacos=tacos地址的值
tacos[3]=*(tacos+3)=tacos+3地址的值
數組名和指針變量都是如此,所以對於指針和數組名,既可使用指針表示法,也可使用數組表示法。
拓展部分
指針和字符串
數組和指針的特殊關係能夠擴展到C-風格字符串。請看下面的代碼:
char flower[10] = "rose"; cout << flower << endl;
輸出結果:
rose
數組名是第一個元素的地址,所以cout語句中的flower是包含字符r的char元素的地址。cout對象認爲char的地址是字符串的地址,所以它打印該地址處的字符,而後繼續打印後面的字符,直到遇到空字符(\0)爲止。總之,若是給cout提供一個字符的地址,則它將從該字符開始打印,直到遇到空字符爲止。
這裏的關鍵不在於flower是數組名,而在於flower是一個char的地址。這意味着能夠將指向char的指針變量做爲cout的參數,由於它也是char的地址。固然,該指針指向字符串的開頭,稍後將覈實這一點。
前面的cout語句中最後一部分的狀況如何呢?若是flower是字符串第一個字符的地址,則表達式「s are red\n」是什麼呢?爲了與cout對字符串輸出的處理保持一致,這個用引號括起的字符串也應當是一個地址。在C++中,用引號括起的字符串像數組名同樣,也是第一個元素的地址。上述代碼不會將整個字符串發送給cout,而只是發送該字符串的地址。這意味着對於數組中的字符串、用引號括起的字符串常量以及指針所描述的字符串,處理的方式是同樣的,都將傳遞它們的地址。與逐個傳遞字符串中的全部字符相比,這樣作的工做量確實要少。
如下例子演示瞭如何使用不一樣形式的字符串。它使用了兩個字符串庫中的函數。函數strlen( )咱們之前用過,它返回字符串的長度。函數strcpy( )將字符串從一個位置複製到另外一個位置。這兩個函數的原型都位於頭文件cstring(在不太新的實現中,爲string.h)中。該程序還經過註釋指出了應儘可能避免的錯誤使用指針的方式。
int main() { char animal[20] = "bear"; const char* bird = "wren"; char* ps; cout << animal << "and"; cout << bird << endl; cout << "Enter a kind of animal:"; cin >> animal; ps = animal; cout << ps << "!\n"; cout << "Before using strcpy():" << endl; cout << animal << " at " << (int*)animal << endl; cout << ps << " at " << (int*)ps << endl; ps = new char[strlen(animal) + 1]; strcpy(ps, animal); cout << "After using strcpy():" << endl; cout << animal << " at " << (int*)animal << endl; cout << ps << " at " << (int*)ps << endl; delete[] ps; return 0; }
下面是程序運行狀況:
程序分析:
程序建立了一個char數組(animal)和兩個指向char的指針變量(bird和ps)。該程序首先將animal數組初始化爲字符串「bear」,就像初始化數組同樣。而後,程序執行了一些新的操做,將char指針初始化爲指向一個字符串:
const char* bird = "wren";
記住,「wren」實際表示的是字符串的地址,所以這條語句將「wren」的地址賦給了bird指針。(通常來講,編譯器在內存留出一些空間,以存儲程序源代碼中全部用引號括起的字符串,並將每一個被存儲的字符串與其地址關聯起來。)這意味着能夠像使用字符串「wren」那樣使用指針bird,以下面的示例所示:
cout<<"A concerned"<<bird<<"speaks";
字符串字面值是常量,這就是爲何代碼在聲明中使用關鍵字const的緣由。以這種方式使用const意味着能夠用bird來訪問字符串,但不能修改它。最後,指針ps未被初始化,所以不指向任何字符串(正如您知道的,這一般是個壞主意,這裏也不例外)
接下來,程序說明了這樣一點,即對於cout來講,使用數組名animal和指針bird是同樣的。畢竟,它們都是字符串的地址,cout將顯示存儲在這兩個地址上的兩個字符串(「bear」和「wren」)。若是激活錯誤地顯示ps的代碼,則將可能顯示一個空行、一堆亂碼,或者程序將崩潰。建立未初始化的指針有點像簽發空頭支票:沒法控制它將被如何使用。
對於輸入,狀況有點不一樣。只要輸入比較短,可以被存儲在數組中,則使用數組animal進行輸入將是安全的。然而,使用bird來進行輸入並不合適:
下面討論一下第二點。C++不能保證字符串字面值被惟一地存儲。也就是說,若是在程序中屢次使用了字符串字面值「wren」,則編譯器將可能存儲該字符串的多個副本,也可能只存儲一個副本。若是是後面一種狀況,則將bird設置爲指向一個「wren」,將使它只是指向該字符串的惟一一個副本。將值讀入一個字符串可能會影響被認爲是獨立的、位於其餘地方的字符串。不管如何,因爲bird指針被聲明爲const,所以編譯器將禁止改變bird指向的位置中的內容。
試圖將信息讀入ps指向的位置將更糟。因爲ps沒有被初始化,所以並不知道信息將被存儲在哪裏,這甚至可能改寫內存中的信息。幸運的是,要避免這種問題很容易—只要使用足夠大的char數組來接收輸入便可。請不要使用字符串常量或未被初始化的指針來接收輸入。爲避免這些問題,也可使用std::string對象,而不是數組。
接下來,請注意下述代碼完成的工做:
ps = animal; //... cout << animal << " at " << (int *)animal << endl; cout << ps << " at " << (int*)ps << endl;
它將生成下面的輸出:
fox at 0049FAA4
fox at 0049FAA4
通常來講,若是給cout提供一個指針,它將打印地址。但若是指針的類型爲char *,則cout將顯示指向的字符串。若是要顯示的是字符串的地址,則必須將這種指針強制轉換爲另外一種指針類型,如int *(上面的代碼就是這樣作的)。所以,ps顯示爲字符串「fox」,而(int *)ps顯示爲該字符串的地址。注意,將animal賦給ps並不會複製字符串,而只是複製地址。這樣,這兩個指針將指向相同的內存單元和字符串。
要得到字符串的副本,還須要作其餘工做。首先,須要分配內存來存儲該字符串,這能夠經過聲明另外一個數組或使用new來完成。後一種方法使得可以根據字符串的長度來指定所需的空間:
ps = new char[strlen(animal) + 1];
字符串「fox」不能填滿整個animal數組,所以這樣作浪費了空間。上述代碼使用strlen( )來肯定字符串的長度,並將它加1來得到包含空字符時該字符串的長度。隨後,程序使用new來分配恰好足夠存儲該字符串的空間。
接下來,須要將animal數組中的字符串複製到新分配的空間中。將animal賦給ps是不可行的,由於這樣只能修改存儲在ps中的地址,從而失去程序訪問新分配內存的惟一途徑。須要使用庫函數strcpy( ):
strcpy(ps, animal);
strcpy( )函數接受2個參數。第一個是目標地址,第二個是要複製的字符串的地址。您應肯定,分配了目標空間,並有足夠的空間來存儲副本。在這裏,咱們用strlen( )來肯定所需的空間,並使用new得到可用的內存。
經過使用strcpy( )和new,將得到「fox」的兩個獨立副本:
fox at 0049FAA4
fox at 004301c8