一. 使用new和delete運算符時PF率的變化情況
Ctrl+Alt+Del進入任務管理器、性能,運行下列代碼,並觀察PF率的變化。可知,new運算符增加PF率,delete使PF率還原。 注意:使用 new 得來的空間,必須用 delete 來釋放;使用 new [] 得來的空間,必須用 delete [] 來釋放。彼此之間不能混用。 用 new [] 分配出連續空間后,指針變量“指向”該空間的首地址。
#include
<
iostream.h
>
#include
<
stdio.h
>

int
main(
int
argc,
char
*
argv[])
{
cout<<"按任意鍵開始分配內存
"<<endl;
getchar();

unsigned char *p = new unsigned char[1024*1024*100];
cout<<"成功分配了100M的內存"<<endl;
getchar();

delete []p;
cout<<"釋放所分配的100M內存"<<endl;
return 0;
}

int
arr[
20
];
//
定義
arr[
0
]
=
100
;
//
讓第一個元素為100
for
(
int
i
=
1
; i
<
20
; i
++
)
{
arr[i] = arr[i-1] + 50;
}
for
(
int
i
=
0
; i
<
20
; i
++
)
//
輸出
{
cout << arr[i] << endl;
}
//
通過+來得到指定元素,也可通過[]
cout
<<
*
(arr
+
0
)
<<
endl;
//
*(arr+0) 等於 *arr
cout
<<
*
(arr
+
1
)
<<
endl;
cout
<<
*
(arr
+
1
)
<<
endl;
指針:
int
*
p
=
new
int
[
20
];
//
定義
p[
0
]
=
100
;
//
讓第一個元素為100
for
(
int
i
=
1
; i
<
20
; i
++
)
{
p[i] = p[i-1] + 50;
}
for
(
int
i
=
0
; i
<
20
; i
++
)
//
輸出
{
cout << p[i] << endl;
}
//
通過+來得到指定元素,也可通過[]
cout
<<
*
(p
+
0
)
<<
endl;
//
*(p+0) 等於 *p
cout
<<
*
(p
+
1
)
<<
endl;
cout
<<
*
(p
+
1
)
<<
endl;
兩者的不同之處:
數組:
//
定義並初始化
int
arr[
10
]
=
{0,1,2,3,4,5,6,7,8,9}
;

//
不能通過對數組本身+或-來改變數組的位置
arr
=
arr
+
1
;
//
錯!
cout
<<
*
arr
<<
endl;
arr
++
;
//
錯!
cout
<<
*
arr
<<
endl;
arr
--
;
//
錯!
cout
<<
*
arr
<<
endl;

//
數組所帶的空間由系統自動分配及回收,無須也無法由程序來直接釋放
指針:
//
定義並且生成空間,但不能直接初始空間的內容
int
*
p
=
new
int
[
20
]
{0,1,2,3,4 ……}
;
//
錯!

//
只得通過循環一個個設置
for
(
int
i
=
0
; i
<
20
; i
++
)
{
p[i] = i;
}

//
可以通過+或-操作直接改變指針
p
=
p
+
1
;
cout
<<
*
p
<<
endl;

p
++
;
cout
<<
*
p
<<
endl;

p
--
;
cout
<<
*
p
<<
endl;

//
指向連續空間的指針,必須使用delete[]來釋放
delete [] p;
三. delete/delete[]的幾個注意點
1. 指針通過 new 或 new[] ,向系統“申請”得到一段內存空間,這段 內存空間必須在不需要將它釋放了。
int
*
p
=
new
int
[
100
];
int
girl[
100
];
p
=
girl;
delete [] p;
災難在 delete [] p
時發生。
我們原意是要釋放p最初通過new int[100]
而得到的內存空間,但事實上,p那時已經指向girl[100]
了。結果,第一、最初的空間並沒有被釋放。第二、girl[100]
本由系統自行釋放,現在我們卻要強行釋放它。
2. 一個指針被刪除時,應指向最初的地址
當一個指針通過 +,- 等操作而改變了指向;那么在釋放之前,應確保其回到原來的指向。如下所示:在 delete [] p 時,p指向的是第二個元素,結果該釋放將產生錯位:第一個元素沒有被釋放,而在最后多刪除了一個元素。
int
*
p
=
new
int
[
3
];

*
p
=
1
;
cout
<<
*
p
<<
endl;

p
++
;
//
p的指向改變了,指向了下一元素
*
p
=
2
;
cout
<<
*
p
<<
endl;

delete [] p;
//
錯誤的釋放
如何消除這一嚴重錯誤呢?
第一種方法是把指針正確地 "倒 "回原始位置:
p
--
;
delete [] p;
但當我們的指針指向變化很多次時,在釋放前要保證一步不錯地一一退回,會比較困難。所以另一方法是在最初時“備份”一份。在釋放時,直接釋放該指針即可。
int
*
p
=
new
int
[
3
];

int
*
pbak
=
*
p;
//
備份

//
移動 p
……

delete [] pbak;
//
釋放
由於
pbak正是指向p最初分配后的地址,我們刪除
pbak,
就是刪除p最初的指向。此時我們不能再刪除一次p。這也就引出new / delete
及 new[] / delete[]
在本章的最后一個問題。
3. 已釋放的空間,不可重復釋放
第一種最直接:
int
*
p
=
new
int
(
71
);

cout
<<
*
p
<<
endl;

delete p;
//
OK!
delete p;
//
ERROR! 重復刪除p
第二種為重復刪除同一指向的多個指針
int
*
p1
=
new
int
(
71
);

int
*
p2
=
p1;
//
p2和p1 現在指向同一內存地址
cout
<<
*
p1
<<
endl;

cout
<<
*
p2
<<
endl;

delete p1;
//
OK
delete p2;
//
ERROR! p2所指的內存,已通過delete p1而被釋放,不可再delete一次
同樣的問題,如果你先刪除了p2
,則同樣不可再刪除p1
delete p2;
//
OK
delete p1;
//
ERROR
第三種為刪除指向某一普通變量的指針
int
a
=
100
;

int
*
p
=
&
a;

delete p;
//
ERROR
Ctrl+Alt+Del進入任務管理器、性能,運行下列代碼,並觀察PF率的變化。可知,new運算符增加PF率,delete使PF率還原。 注意:使用 new 得來的空間,必須用 delete 來釋放;使用 new [] 得來的空間,必須用 delete [] 來釋放。彼此之間不能混用。 用 new [] 分配出連續空間后,指針變量“指向”該空間的首地址。



















二. 指向連續空間的指針
在通過 new [] 指向連續空間以后,p 就變得和一個一維數組很是類似。我們先來復習一下數組相關知識。假設是這么一個數組: int arr[20]; 則arr 的內存示意圖為
和指針變量相比,數組沒有一個單獨的內存空間而存放其內存地址。即:指針變量p是一個獨立的變量,只不過它的值指向另一段連續的內存空間;而數組arr,本身代表的就是一段連續空間。
數組是“實”的地址,不能改變。當你和定義一個數組,則這個數組就得根據它在內存中的位置,得到一個地址,如上圖中的“0x1A000000”。只要這個數組存在,那么它終生的地址就是這個值。
指針是一個“虛”的地址,可以改變地址的值。當你定義一個指針變量,這個變量占用4個字節的內存,你可以往這4字節的內存寫入任意一個值,該值被當成一個內存地址。比如,你可以寫入上面的“0x1A000000”,此時,指針p指向第一個元素。也可以改為“0x1A000003”,此時,指針p指向第二個元素。
所以,當p通過 new [] 指向一段連續空間的結果是,p 是一個指向數組的指針,而*p是它所指的數組。
兩者的相似之處:
數組:














指針:














兩者的不同之處:
數組:












指針:





















三. delete/delete[]的幾個注意點
1. 指針通過 new 或 new[] ,向系統“申請”得到一段內存空間,這段 內存空間必須在不需要將它釋放了。




2. 一個指針被刪除時,應指向最初的地址
當一個指針通過 +,- 等操作而改變了指向;那么在釋放之前,應確保其回到原來的指向。如下所示:在 delete [] p 時,p指向的是第二個元素,結果該釋放將產生錯位:第一個元素沒有被釋放,而在最后多刪除了一個元素。











第一種方法是把指針正確地 "倒 "回原始位置:



但當我們的指針指向變化很多次時,在釋放前要保證一步不錯地一一退回,會比較困難。所以另一方法是在最初時“備份”一份。在釋放時,直接釋放該指針即可。










3. 已釋放的空間,不可重復釋放
第一種最直接:







第二種為重復刪除同一指向的多個指針















第三種為刪除指向某一普通變量的指針





p 不是通過new 得到新的內存空間,而是直接指向固定變量a。所以刪除p等同要強行剝奪a的固有空間,會導致出錯。
因為我需要釋放指向二維結構體指針的指針,為測試內存釋放情況,改寫程序。代碼如下:
- #include<iostream>
- #include<stdio.h>
- using namespace std;
- void main()
- {
- cout << "指針變量占4字節內存。按回車鍵開始分配404M內存..." << endl;
- int temp;
- getchar();
- int x = 100;
- int y = 1024*1024;
- char ***p = new char** [y];
- for(int i=0; i<y; ++i)
- {
- p[i] = new char*[x];
- }
- cout << "內存分配完畢,按回車鍵開始清理內存..." << endl;
- getchar();
- for (int i=0; i<y; ++i)
- {
- delete []p[i];
- }
- cout << "二位數組,第二維清理完畢,共清理內存400M,剩余4M未清理,按回車鍵繼續清理..." << endl;
- getchar();
- delete []p;
- p = NULL; //如果不對p賦值NULL,再次清理內存,將報錯
- /*cout << "再次清理內存..." << endl;
- getchar();
- delete []p;
- p = NULL;*/
- cout << "內存清理完畢..." << endl;
- getchar();
- }
#include<iostream> #include<stdio.h> using namespace std; void main() { cout << "指針變量占4字節內存。按回車鍵開始分配404M內存..." << endl; int temp; getchar(); int x = 100; int y = 1024*1024; char ***p = new char** [y]; for(int i=0; i<y; ++i) { p[i] = new char*[x]; } cout << "內存分配完畢,按回車鍵開始清理內存..." << endl; getchar(); for (int i=0; i<y; ++i) { delete []p[i]; } cout << "二位數組,第二維清理完畢,共清理內存400M,剩余4M未清理,按回車鍵繼續清理..." << endl; getchar(); delete []p; p = NULL; //如果不對p賦值NULL,再次清理內存,將報錯 /*cout << "再次清理內存..." << endl; getchar(); delete []p; p = NULL;*/ cout << "內存清理完畢..." << endl; getchar(); }