討論區快速選單
知識庫快速選單
網路投保旅行平安險 軟體開發過程中有哪些資安漏洞? 掌握Salesforce雲端管理秘訣
[ 回上頁 ] [ 討論區發言規則 ]
關於指標的new、delete、NULL的觀念問題
更改我的閱讀文章字型大小
作者 : jojozerox(jojozerox)
[ 貼文 45 | 人氣 6735 | 評價 10 | 評價/貼文 0.22 | 送出評價 4 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/25 下午 01:26:03
小弟最近處碰指標的部份因此有一堆觀念被搞混
請各位大大能幫小弟解決以下這些問題
感激不盡m(_ _)m

<1>
指標的好處就是節省記憶體空間,那為什麼有的時候宣告變數不使用指標
而是使用一般的宣告方式,如下兩種方式宣告,但是目的都只是放數值
int *p;
*p=111;//假設放入111的值

int p;
p=111;
向這種情況下大部分還是使用int p
是不是因為方便的關係,所以不使用指標??


<2>
有的時候使用指標要加上new才可以使用
int *p=new int;
可是宣告的時候不就已經有配置記憶體了嗎?
為啥還要使用new從新配置??


<3>
宣告指標時使用new和NULL有啥差別???
int *p=new int;

int *p=NULL;
兩者差異????????


<4>
我知道使用new的話,當不使用指標時必須最後delete
但是如果的指標是在區域環境下宣告
那還需要delete嗎????


<5>
我發現delete有兩種就是delete和delete[ ]
delete給一般指標專用???
delete[ ]難道是給多維指標陣列使用嗎??
用錯地方會不會沒有效過???

<6>
如果使用了結構指標
是否還需要delete???
delete的方法是否和指標一樣???


這是目前遇到的一些渾淆觀念O_O
希望知道答案的大大能夠幫助回答
另外請把我當白癡詳細教...感恩:D
作者 : chiuinan2(青衫)討論區板主 Visual C++ .NET卓越專家VC++一代宗師Visual Basic優秀好手資訊類作業求救卓越專家一般曠世奇才程式設計甘苦談優秀好手C++ Builder優秀好手上班族的哈拉園地優秀好手C++頂尖高手Assembly優秀好手貼文超過3000則人氣指數超過150000點
[ 貼文 3732 | 人氣 170106 | 評價 34520 | 評價/貼文 9.25 | 送出評價 125 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人jojozerox註記此篇回應為最佳解答 2008/1/25 下午 04:17:17
什麼是指標? 就是本身是用來記錄"位址"的變數, 或者你可以想像它的值是用來指向某個空間. 例如:

int a;
int *b = &a;

b記錄的便是變數a所在空間的位址, 也就是指向變數a所在的地方. 因此*b=10的結果, 便是將10填入b所指的地方, 也就是變數a的實體空間裡. 其結果跟a=10是一樣的.

void* p;

這樣的寫法表示, p指向的是一個空間, 但這個空間裡記錄的是什麼結構, 不知道. 因此在不知指向的空間是什麼結構前, 你無法直接填值進去, 必須另外轉型才行.

char** p;

這樣的話, p指向的空間裡, 是記錄char*這樣的結構 (也就是再記錄一個位址值), 因此*p存取到的, 都是位址值. 取到位址值後, 必須再指向一次, 才能得到實際的空間, 也就是**p才是指向記錄char這個結構的空間.

陣列變數其實也可以視為指標來看待:

int p1[10];
int *p2 = p1;

p1與p2指向的空間位址都是一樣的, 只不過p1是立刻可以知道是一個連續10個int空間的陣列, p2的話, 只知道是指向一個記錄int的空間, 是不是陣列則是程式撰寫者才知道. 在這個例子中, 因為已經知道p2指向的是一個int陣列, 所以可以用p2[5]這樣的方式來存取陣列內容, 或者也可以寫成*(p2+5), 它的意義則是p2指向的位址再往下5個結構, 然後存取裡面的值. 因為已經知道p2指向的空間裡, 記錄的是int結構, 所以再往下5個int便是第6個int空間, 跟p2[5]是相同的.

int p1[10][20];
int **p2;

二維以上的陣列與指標就有點不同了, p1是指向一個一大塊的空間, 這個空間被規劃成10x20個int, p2則是指向一個int*的空間, 然後再從該空間裡記錄的位址再去存取實際的內容, 這種方法為間接存取. 假設p2是被做成跟p1一樣10x20維度的陣列, 那麼p2在空間的運用上也與p1不同. 因為p1指向的空間是一整塊, 維度也是已知 (必須是已知), 所以p1[i][j]馬上可以知道是在記錄空間裡的那一個地方, 但p2就不同了. p2必須是先指向一個int*[10]的空間, 每個空間分別指向int[20]的空間, 因此實際的空間並非一大塊, 而是拆成11個 (其中一個是用來存放其他空間的位址用的), 因此p2[i][j]實際上是先p2[i]從int*[10]空間裡取到指標值, 然後再經由這個指標值再做[j]得到實際的空間, 然後進行存取. 我記得Raymond曾畫過不少關於這類指標的圖, 試著搜尋看看吧, 比較容易了解一些.

有了以上的基礎知識後, 你的問題才比較好回答:

><1>
>指標的好處就是節省記憶體空間

指標的好處不是節省記憶體, 大部份的情況反而比較浪費記憶體. 但指標的目的, 多半是要做彈性的處理, 特別是不知道資料量大小的情況下, 往往必須使用動態記憶體, 此時便需要配合指標來處理. 這點需要你再慢慢去體會吧.

>如下兩種方式宣告,但是目的都只是放數值
>int *p;
>*p=111;//假設放入111的值
>和
>int p;
>p=111;
>向這種情況下大部分還是使用int p
>是不是因為方便的關係,所以不使用指標??

int* p;
*p=111;

p是用來指向一個int空間, 但你沒給初值, 也就是不知指向那裡, 因此將111存入不知那個地方, 一定會出問題. 指標變數本身的空間 (也是有佔用空間唷), 是用來記錄位址, 你填入p的值必須是某個空間的位址, 在p沒指向一個切確的空間前, 是不能去存取它指向的空間內容. 即使有指向某個空間, 也要看該空間還是否合法, 像指向的動態記憶體被釋放掉了, 或是指向的區域變數已離開它所在的scope等, 這時原指向的空間已消失, 再去存取, 往往會造成許多問題.

int p;
p=111;

這樣的變數p, 本身空間是一個整數, 因此存取的, 都是整數值.

每個變數宣告後, 都會佔用一定的空間, 至於佔用多少空間, 便視它的形態而定. 而存取的內容是什麼, 也是依變數的形態而定. 前例中, int*p, p佔用sizeof(int*)空間, 存取的內容是int*結構的位址值, int p, p佔用sizeof(int)空間, 存取的內容是int結構的整數值.

作者 : chiuinan2(青衫)討論區板主 Visual C++ .NET卓越專家VC++一代宗師Visual Basic優秀好手資訊類作業求救卓越專家一般曠世奇才程式設計甘苦談優秀好手C++ Builder優秀好手上班族的哈拉園地優秀好手C++頂尖高手Assembly優秀好手貼文超過3000則人氣指數超過150000點
[ 貼文 3732 | 人氣 170106 | 評價 34520 | 評價/貼文 9.25 | 送出評價 125 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/25 下午 04:17:30
><2>
>有的時候使用指標要加上new才可以使用
>int *p=new int;
>可是宣告的時候不就已經有配置記憶體了嗎?
>為啥還要使用new從新配置??

前面已提過, 宣告所配置的記憶體, 是變數本身的記憶體 (以此例便是用來記錄int*的記憶體), 問題是p目前還沒有值, 要如何給值呢? 你可以給另一個int空間(或int陣列)的位址給它, 但更常見的, 便是用new配置動態記憶體空間給它. 沒有給值前, p的內容是沒有意義, *p也就不知指到那裡去, 存取一個隨機某處的記憶體, 不當掉才怪.

><3>
>宣告指標時使用new和NULL有啥差別???
>int *p=new int;
>和
>int *p=NULL;
>兩者差異????????

指標變數在給初值時, 除了立即配置給予一個空間位址外, 也可以直接給予NULL, 表示還沒指向任何空間. 因為還沒指向任何空間, *p一樣會出問題. 給NULL的目的, 通常是為了用來判斷, 例如:

if (p == NULL) ...

可以用來得知, p是否已指向一個合法空間. 當然是否給NULL值是程式撰寫者必須自己控制的, 當p指向的空間已消滅時, 便要立刻將p再設成NULL, 表示已不再指向任何空間, 如此前述這樣的比較才有意義. 所以使用指標是必須多費一點心, 不然除錯起來可是很困難的.

><4>
>我知道使用new的話,當不使用指標時必須最後delete
>但是如果的指標是在區域環境下宣告
>那還需要delete嗎????

並不是不使用指標時才delete, 而是不再使用該動態記憶體時, 這點跟指標沒關係. 例如:

int *p1 = new int[10];
int *p2 = p1;

現在主要看int[10];這個動態記憶體空間什麼時候不再使用, 不再使用時便delete. 此例裡, p1不再使用時, 還有p2指向這個空間. 但要記得, 動態記憶體空間一定要有一個指標指向它的頭, 不然就無法delete掉了.

至於離開區域環境, 消失的是指標變數的空間, 也就是原本用來記錄動態記憶體空間位址的空間會消失, 但已配置的動態記憶體還是存在的 (這裡雖有一些小例外, 但非常態), 因此在離開前若不再使用動態記憶體, 都必須delete掉, 不然就會有memory leak.

><5>
>我發現delete有兩種就是delete和delete[ ]
>delete給一般指標專用???
>delete[ ]難道是給多維指標陣列使用嗎??
>用錯地方會不會沒有效過???

delete[]主要是用來釋放物件陣列的動態記憶體空間. 例如:

class a {...};

a* b = new a[10];

此時配置的動態空間會視為10個a物件, 然後分別呼叫a的建構函數 (因有10個, 故會呼叫10次).

delete[] b;

在釋放前, 知道b是一個陣列 (加[]的目的), 因此會分別呼叫10個a物件裡解構函數 (共10次).

delete b;

這樣的寫法, 則是將b視為指向一個a物件 (非陣列), 因此只會呼叫第1個a物件裡的解構函數 (共1次)

一般的原則是, new後面有[]的, 在delete時, 也要加上[], new後面沒[]的, delete時便不要加, 這樣就不會出錯了.

><6>
>如果使用了結構指標
>是否還需要delete???
>delete的方法是否和指標一樣???

結構指標? 不懂你所指的意義.
作者 : franklin(doggie) C++優秀好手
[ 貼文 156 | 人氣 11 | 評價 750 | 評價/貼文 4.81 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/25 下午 04:54:09

><1>
>指標的好處就是節省記憶體空間,那為什麼有的時候宣告變數不使用指標
誰說的...如果是書上寫的....請把書撕了吧

>而是使用一般的宣告方式,如下兩種方式宣告,但是目的都只是放數值
>int *p;
>*p=111;//假設放入111的值
>和
>int p;
>p=111;
>向這種情況下大部分還是使用int p
>是不是因為方便的關係,所以不使用指標??
不是,是因為第一種寫法完全是錯誤的

指標是一種特殊的變數
它代表的不是資料本身
而是資料的位址
我們可以改變指標的值讓它指向不同的位址
然後使用*操作它指向的位址裡的資料
例如
int i= 0; //配置了一個int變數i, 並設定初始值為0
int *p; //配置了一個int指標變數p
p= &i; //p指向變數i的空間
*p= 111; //設定p指向空間的值為111
printf( "%d", i); //此時i的值已經透過p被改變成111了, 所以這裡將會印出111

回到你的問題
第一種寫法配置了一個指標變數但沒有設定它指向的地方
運氣好的話它的初始值指向一個未配置的空間
程式一執行就給你一個Segmentation fault錯誤訊息
運氣不好的話它會指到一個配置好的空間
讓你的設值動作影響到別的運算
影響到你的程式結果又讓你難以發現錯在那

><2>
>有的時候使用指標要加上new才可以使用
>int *p=new int;
>可是宣告的時候不就已經有配置記憶體了嗎?
>為啥還要使用new從新配置??
int *p;配置的空間是一個指標
而不是int變數

><3>
>宣告指標時使用new和NULL有啥差別???
>int *p=new int;
>和
>int *p=NULL;
>兩者差異????????
NULL是個特殊位址
用來表示這個指標並沒有指向任何位址

><4>
>我知道使用new的話,當不使用指標時必須最後delete
>但是如果的指標是在區域環境下宣告
>那還需要delete嗎????

new並不是一種宣告

><5>
>我發現delete有兩種就是delete和delete[ ]
>delete給一般指標專用???
>delete[ ]難道是給多維指標陣列使用嗎??
>用錯地方會不會沒有效過???
delete是對映new操作產生的物件
delete []是對映new []操作產生的物件陣列
範例
int *p= new int[ 10];
delete [] p;
這個用錯會造成memory leak

><6>
>如果使用了結構指標
>是否還需要delete???
>delete的方法是否和指標一樣???
你的結構指標是指什麼?

基本上用new產生的就必須delete
用alloc系列函式產生的就必須free
跟用什麼指標無關

作者 : jojozerox(jojozerox)
[ 貼文 45 | 人氣 6735 | 評價 10 | 評價/貼文 0.22 | 送出評價 4 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/25 下午 05:11:13
><6>
>如果使用了結構指標
>是否還需要delete???
>delete的方法是否和指標一樣???
你的結構指標是指什麼?

感謝大大的解說O_Oa
至於第六個的問題指標結構就是如下

typedef struct abc
{
int data;
}

abc *p;

p->data=1000;//假設給值

當最後不使用的時候
是不是和一般指標一樣
delete p;??????
作者 : chiuinan2(青衫)討論區板主 Visual C++ .NET卓越專家VC++一代宗師Visual Basic優秀好手資訊類作業求救卓越專家一般曠世奇才程式設計甘苦談優秀好手C++ Builder優秀好手上班族的哈拉園地優秀好手C++頂尖高手Assembly優秀好手貼文超過3000則人氣指數超過150000點
[ 貼文 3732 | 人氣 170106 | 評價 34520 | 評價/貼文 9.25 | 送出評價 125 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人jojozerox註記此篇回應為最佳解答 2008/1/25 下午 06:02:09
>至於第六個的問題指標結構就是如下
>
>typedef struct abc
>{
>int data;
>}
>
>abc *p;
>
>p->data=1000;//假設給值
>
>當最後不使用的時候
>是不是和一般指標一樣
>delete p;??????

無論指標指向的結構是class, struct, 或是一般的純資料 (如char, int, float等), new和delete的對應方式都一樣. 因此:

abc *p = new abc;
對應的便是delete p;

abc *p = new abc[10];
對應的便是delete[] p;

附帶再說一下. 該用delete[]卻用delete, 其實未必會出問題, 像純資料char, int等, 本身沒有解構函數, 或是像你例子中的struct也沒有解構函數, 因此用delete與用delete[]並沒有差, 也不會造成memory leak. 例如:

int *p = new int[10];
delete p; 與delete[] p; 作用是相同的.

不過當有解構函數時, delete與delete[]就不同了, 當用delete[]卻誤用delete便可能出問題. 因此為養成良好習慣, 前例還是使用delete[] p;較佳.
作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/25 下午 09:05:05
><4>
>我知道使用new的話,當不使用指標時必須最後delete
>但是如果的指標是在區域環境下宣告
>那還需要delete嗎????

只要用到指標, 就意味著有兩個物件: 第一個是指標本身的內容; 第二個是指標所指向的空間:

  {
    int *p = new int;
    ...
  }

    int *
   +=====+      +=======+
  p| *---+----> | <int> |
   +=====+      +=======+

'p' 是個區域自動物件, 在離開包起它的 {} 時會自動消失.

但 'p' 所指向的空間是 new 出來的, 它會一直存活到你去 delete 為止.

兩個不同的物件, 要分開思考處理.

作者 : jojozerox(jojozerox)
[ 貼文 45 | 人氣 6735 | 評價 10 | 評價/貼文 0.22 | 送出評價 4 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/29 下午 07:54:48
感謝各位大大的回答:D
對於指標我目前只剩一個小問題了

也就是不管我在全域或是區域下宣告指標
最後都一定要delete...

但是我測試了一下
我在副程式的地方使用了指標
並且回傳的值是指標
假設副程式如下

float* abc(int a)
{
 float * b=new float[2];

  b[0]=a*1;
  b[1]=a*2;

 return(b);
}

問題來了...這種情形下我要回傳指標
所以我沒辦法delete
因為我在主程式的地方呼叫完副程式後加入
delete b;

可是程式卻會說這行錯誤O_Oa

所以是不是表示副程式的指標不用delete
或者是因為我把副程式寫再另一個*.h檔裡面
所以導致不用delete???
作者 : akasan(akasan)
[ 貼文 147 | 人氣 1174 | 評價 470 | 評價/貼文 3.2 | 送出評價 0 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人jojozerox註記此篇回應為最佳解答 2008/1/29 下午 08:13:43
oh

指標是指標

記憶體是記憶體


so

int *ptr = abc(10);
delete ptr;

而不是

int *ptr = abc(10);
delete b;

不要被形式上的變數名稱給綁住了
作者 : chiuinan2(青衫)討論區板主 Visual C++ .NET卓越專家VC++一代宗師Visual Basic優秀好手資訊類作業求救卓越專家一般曠世奇才程式設計甘苦談優秀好手C++ Builder優秀好手上班族的哈拉園地優秀好手C++頂尖高手Assembly優秀好手貼文超過3000則人氣指數超過150000點
[ 貼文 3732 | 人氣 170106 | 評價 34520 | 評價/貼文 9.25 | 送出評價 125 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/30 上午 12:14:57
>感謝各位大大的回答:D
>對於指標我目前只剩一個小問題了
>
>也就是不管我在全域或是區域下宣告指標
>最後都一定要delete...

感覺上, 你對指標還是有點似懂非懂的. 我直接用淺顯的例子來說明好了. 指標也是一種存"值"的變數, 跟整數變數, 浮點數變數一樣, 只不過它存的是位址值而已.

int a;

&a傳回來的, 是a這個變數的所在位址, 假設位址值就是1234, 那麼:

int* b = &a;

b所存的值就是1234, *b就是要去存取位址1234這個記憶體裡面的資料. 就好像是門牌號碼一樣, 門牌號碼表示是那一棟房子, 但房子裡裝的是什麼就不一定, b表示的便是門牌號碼, 而*b則是到它代表的房子裡去存取資料.

new/delete的作用, 就好像有一堆空房子, new是找一個空房子, 然後傳回該門牌號碼 (位址值), delete便是告知門牌號碼, 表示這個房子不再使用了. 因此

int* b = new int[10];

new int[10];會傳回一個位址值, 假設是5678, 然後放到b這個變數裡. 當不用時, 便要將5678這個位址值傳回給delete做釋放的動作, 因為b的值是5678, 所以delete b剛好就是將原先new出來的記憶體給釋放掉. 如果多做了一個:

b++;

那麼b的值變掉了 (假設是5679), 這樣跟原先new傳回來的位址不同, 此時delete b已不是原先new出來的記憶體位址, 就會造成問題.

你的例子也是相同:

float* abc(int a)
{
 float * b=new float[2];

  b[0]=a*1;
  b[1]=a*2;

 return(b);
}

float* c = abc(10);

在abc函數裡new出來的位址值, 假設是2345, 那麼最後return b;就是將位址值2345傳出去, 於是c的值變成位址2345, 這時delete c就可以釋放new出來的那一塊記憶體 (位址2345). 如果你在abc裡有delete b;又傳回b的值, 會變成怎樣? 就會變成, 我申請了一個空房子, 告訴外面呼叫該函數的人xxx門牌號碼的房子可以用, 但卻又釋放回系統, 讓其他的人可以再申請到這個房子使用. 最後就可能造成多個人共用同一個房子, 而造成衝突.

如果裡面外面都沒有delete呢? 就變成申請了一個空房, 不用時就擺著不管. 下次想用時, 又要了另一個空房. 由於空房 (記憶體) 有限, 不用的空房佔著不放, 最後可能就全部用盡了, 再也沒多的空房可用.

這樣的講解應該比較容易理解吧? 指標變數只是在記錄"位址值", 所有對指標變數的運算與傳遞, 都是在處理這個位址值. 因此:

int a = 10;
int* b = &a;
char* c = (char*)b;
void* d = c;

b, c, d的值都一樣, 都是a所在的"位址值". *之前的, 就是表示這個位址所在的記憶體是什麼資料形態, 相當於宣告門牌號碼代表的房子裡, 是放什麼東西一樣.

使用new/delete或是malloc/free得到的便是動態配置出來的記憶體位址, 它需要指標變數來記錄這個位址值. 一但配置後, 不管這個位址值傳到那裡去, 最後一定要在某一個地方做釋放的動作, 不然系統就認為這塊記憶體一直被使用中, 不會再拿來使用.

所以請認清楚, 指標只是記錄"位址值", 要不要釋放, 什麼時候釋放, 便看你的用途而定. 像:

int a;
int* b = &a;

這時就不能用delete b; 因為a不是動態記憶體, 它的位址便不能隨便釋放. 這點就好像已有人的住家, 先借用它的門牌號碼來用, 然後卻把它給釋放掉, 讓系統視為空屋處理, 想當然就會出問題.

總之, 處理指標, 就必須有"位址值"的概念與想法, 否則常會搞混與出錯.
作者 : kagaya(kagaya) VC++優秀好手C++優秀好手貼文超過1000則人氣指數超過30000點
[ 貼文 1602 | 人氣 38709 | 評價 4610 | 評價/貼文 2.88 | 送出評價 115 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/30 上午 09:36:39
先不談其它的
你的b宣告在函式裡 是個區域變數
但你卻想在區域外操作b
你的想法基本上就有錯了
作者 : jojozerox(jojozerox)
[ 貼文 45 | 人氣 6735 | 評價 10 | 評價/貼文 0.22 | 送出評價 4 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/30 下午 07:28:20
回樓上的
可能是我的問題沒說的很清楚@@a

因為副程式的裡面b是指標
而且已經有配置一塊記憶體給b了
但是因為要return回去
又不能在return之前delete
也沒辦法寫在returm下面delete

所以我才被這個問題困擾
所以這個問題就是這種情況b到底要不要delete
如果需要的話
是要怎麼delete??
作者 : chiuinan2(青衫)討論區板主 Visual C++ .NET卓越專家VC++一代宗師Visual Basic優秀好手資訊類作業求救卓越專家一般曠世奇才程式設計甘苦談優秀好手C++ Builder優秀好手上班族的哈拉園地優秀好手C++頂尖高手Assembly優秀好手貼文超過3000則人氣指數超過150000點
[ 貼文 3732 | 人氣 170106 | 評價 34520 | 評價/貼文 9.25 | 送出評價 125 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/30 下午 08:37:47
...

麻煩看一下我的說明, 再仔細想想, 答案已在裡面了. 這裡再明白的指出:

float* abc(int a)
{
 float * b=new float[2];

  b[0]=a*1;
  b[1]=a*2;

 return(b);
}

int main(void)
{
float* c = abc(10);
// 呼叫後, 函數abc裡new出來的記憶體已被傳出, 現在記錄在指標c裡 //
// 這時可以開始用指標c指向的記憶體 //
delete c; // 不用時便釋放 //
}

作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/30 下午 09:16:40
>因為副程式的裡面b是指標
>而且已經有配置一塊記憶體給b了
>但是因為要return回去
>又不能在return之前delete
>也沒辦法寫在returm下面delete
>
>所以我才被這個問題困擾
>所以這個問題就是這種情況b到底要不要delete
>如果需要的話
>是要怎麼delete??

先不管指標, 用 int 來看看 return 是個怎樣的情況:

  int func(void)
  {
    int func_i = ...;
    ...
    return func_i;
  }

  int main(void)
  {
    int main_i;
    ...
    main_i = func();
    ...
  }

在副程式 func() 結束前, 它傳回 func_i, 然後 func() 就結束. 在 func() 裡面的自動變數 func_i 也當然就消失了.

但這個會有問題嗎? 沒有!

因為在 func() 結束, func_i 消失前, return func_i 會把 func_i 的內容複製到主程式裡的 main_i 變數.

  main()    |   func()
------------+-----------
            |
   mainˍi   |   funcˍi
  +======+  |  +======+
  |      |  |  |      |
  +======+  |  +======+
      ︿     |      |
      |     |      |
      +------------+
            |

這裡有一個很重要的重點, 就是『複製內容』, func_i 的內容.

現在把 func_i 及 main_i 的類型改成指標, 變數名字也稍微改了一下, 以免在敘述中跟上面的混淆. 同樣的, func() 的回傳類型也要改成指標類型:

  int* func(void)
  {
    int* func_p = ...;
    ...
    return func_p;
  }

  int main(void)
  {
    int* main_p;
    ...
    main_p = func();
    ...
  }

return func_p 所複製的也是『指標的內容』. 我在之前的回覆裡就已經強調, 「指標」意味著有兩個不同的東西: 指標的內容, 及所指向的空間.

回傳指標物件所傳回的是指標的內容. 既然所複製的是指標的內容, 所以 main_p 所指向的也就是之前 func_p 所指向的空間.

  main()    |   func()
------------+-----------
複製前:        |
            |
   mainˍp   |   funcˍp
  +======+  |  +======+     +===+
  |      |  |  | *----+---->|   |
  +======+  |  +======+     +===+
            |
            |
複製:         |
   mainˍp   |   funcˍp
  +======+  |  +======+
  |      |  |  |      |
  +======+  |  +======+
      ︿     |      |
      |     |      |
      +------------+
            |
複製後:        |
   mainˍp   |   funcˍp
  +======+  |  +======+     +===+
  |  *   |  |  | *----+---->|   |
  +==|===+  |  +======+     +===+
     |                        ︿
     |                        |
     +------------------------+

〔續...〕
作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++一代宗師新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4945 | 人氣 9172 | 評價 32290 | 評價/貼文 6.53 | 送出評價 142 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/30 下午 09:16:57
〔...續〕

現在看回你的程式 (只顯示有關的部份):
  float* abc()
  {
    float *b = new ...;
    ...
    return b;
  }

  int main()
  {
    float *c = abc();
  }

在回傳的過程中, 變數 'b' 的內容複製到變數 'c' 裡. 所以 'c' 也指向 'b' 所 new 出來的空間.

在 abc() 結束後, 'b' 會消失, 但它所指向的內容, 由於是 new 出來的, 還存在. 而這個配置出來的空間, 在 main() 裡面變成是用 c 來指著.

delete 所在乎的是指標的內容, 而不是哪個變數.

你不可能在 main() 裡面 delete b, 但 delete c 是可以的:

  int main()
  {
    float *c = abc();
    ...
    delete [] c;
    ...
  }

作者 : nietzsche(尼采) VC++優秀好手C++優秀好手貼文超過500則
[ 貼文 501 | 人氣 3089 | 評價 2900 | 評價/貼文 5.79 | 送出評價 5 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2008/1/30 下午 09:30:54
float* abc(int a)
{
 float * b=new float[2];

  b[0]=a*1;
  b[1]=a*2;

 return(b);
}

基本上不鼓勵"外部刪除配置的記憶體"這件事, 你提供了一個 abc 函數,
函數內 配置 了記憶體, 就要有另一個成對的函數來刪除記憶體.

void deletePtr( float* ptr )
{
 delete ptr;
}

函數是你寫的, 你自己都知道是用 new 或 malloc 去配置, 能正確的釋放,
但是, 如果你的 abc() 是做成 lib 給別人使用, 別人根本無法得知該用
delete 還是 free 去釋放記憶體.

另外, 假設
float* pf= new float;
float* ptr1= pf;
float* ptr2= prt1;

以下的各個作法, 效果都是相同的, 但只能做其中一種.
delete pf;

delete ptr1;

delete ptr2;
都可以.

所以你的 abc 函數, 不必急著在函數裡直接刪除, 因為你配置記憶體, 並想把
指標 return 回去繼續使用, 如果在函數內就把記憶體刪除了, 那 return 那段
就沒意義了不是嗎?
等你的指標確定不使用了, 再進行記憶體的釋放即可.

不要執著於 abc() 函數裡的變數名稱 b. 再說, 如果你使用 malloc( ) 這個函數,
你也不必去知道 malloc 裡使用了什麼變數, 該怎麼針對那個變數去釋放, 不是嗎?
而且使用 abc() 的方式, 應該必須是:
float* ptr= abc( 3 ); // 方法 ( 1 )
而不能是:
abc( 3 ); // 方法 ( 2 )
即然如此, 你拿到了 ptr, 就可以針對 abc()裡配置的記憶體作釋放了.
如果使用者用了方法2, 這樣就會造成 memory leak, 這也不是原本設計 abc() 時
所預想的.
方法2的意思, 就跟你使用:
new int;
意思一樣, 沒有任何參考或指標去記錄這個配置記憶體行為, 你就無法去釋放.
 板主 : simula
 > C++ - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - C++ - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
C++
1 Raymond 13050 
2 青衫 4760 
3 simula 4690 
4 coco 4030 
5 白老鼠(Gary) 3670 
6 ozzy 2540 
7 Ben 2250 
8 Anderson 1960 
9 windblown 1650 
10 Kenny 1560 
C++
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2019 程式設計俱樂部 http://www.programmer-club.com.tw/
0.203125