程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 編程練習之數組與指針,編程數組指針

編程練習之數組與指針,編程數組指針

編輯:關於C語言

編程練習之數組與指針,編程數組指針


數組與指針

閱讀如下代碼,為何出錯。

 1 int main() {  
 2     char a[] = { "I am a bad boy" };  
 3     char * pA = new char[ sizeof( a ) ];  
 4     pA = a;  
 5       
 6     for ( size_t i = 0; i < sizeof( a ); ++i ) {  
 7         std::cout << *pA << std::endl;  
 8         ++pA;  
 9     }  
10     delete [] pA;  
11     pA = NULL;  
12     return 0;  
13 }

我們把那段魔術字符串命名為x。

第一步我們將字符串x存入了棧空間;第二步我們試圖在堆空間申請一塊可以正好存放x的的內存。以上兩步都做得很對,但第三步大有問題。

本意是企圖將x復制入堆內存中,但實際操作的結果是將指針指向了原x所在的棧空間。這將導致一個內存洩漏。(要注意的是string類的等於號能夠賦值是因為操作符的重載)。接下來是遍歷整個字符串,運行結果仿佛復制成功了一樣,但實際上你是在遍歷存在於棧空間的x。遍歷的過程中還不斷修改指針指向的值,因為分配字符串時最後會自動添加一個空字符串(等價於NULL或0),指針最終指向了棧空間的x末尾的空字符串處。企圖釋放棧空間導致的爆炸就更不用說了。

 

代碼如何修改才正確呢?

 1 int main() {  
 2     char a[] = { "I am a bad boy" };  
 3     char * pA = new char[ sizeof( a ) ]; 
 4     strcpy( pA, a );    
 5     for ( size_t i = 0; i < sizeof( a ); ++i ) {  
 6         std::cout << *( pA + i );  
 7     }  
 8     delete [] pA;  
 9     pA = NULL;  
10     return 0;  
11 }  

將字符串拷貝到堆內存分配的空間中,需要用到c函數strcpy,將值拷貝過去。你也可以將x的每一個字符賦值過去。注意,千萬盡量不要改變指向堆內存首個位置的指針,如果你有把握還原回去的話。釋放一定要從堆內存首部分開始,不然也會導致爆炸。

 

期間你有可能會忽略這些問題。

(1)

1 ++pA;

上面已經提到過了,沒有把握釋放的是首位的話盡量不要改變指針的指向。你可以使用指針的偏移或數組下標來進行操作

(2)

1 char * pA = new char[ strlen( a ) ]; 

要注意strlen不計空字符的,因此堆內存分配時中會少一個存放空字符的空間,導致很多函數不能在這段字符結束時停止讀取。

1 char * pA = new char[ strlen( a ) + 1 ]; 

多分配一個即可,或你可以使用sizeof(注意 sizeof 指向堆內存指針 為指針的大小)。

(3)

你可能會這樣釋放數組堆內存。

1 delete pA;  

編譯運行,沒有任何問題。但這是一個未定義行為(UB),在不同的平台或編譯器下運行結果可能不同,總之這是一個潛在的危險操作,你應該讓自己嚴格使用delete[]去釋放數組堆內存。

 

後記:

提到了string重載的等號。對於熟悉C/C++的人在這方面不會有任何問題,但對於初學者這可能確實不太好理解和弄懂。我一直不使用重載操作符或許和這也有關系吧。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved