作者tropical72 (藍影)
看板C_and_CPP
標題Re: [問題] auto宣告的記憶體問題
時間Thu Jan 19 18:54:45 2012
我先說結論,
你在 auto 那裡看到的「動態」、「靜態」的修飾全都拿掉,
一方面他的語意讓大多學子誤會 (我相信筆者本意也不是如此),
另一方面照他邏輯走也不完全正確。
由於這本書我沒全看完 (其中一個原因是我覺得有時敘述會讓人有點誤解)
我們暫時拋棄你手邊書本的語意,換個說法來過。
同時我也只針對你書本之文意做部份說明,太深入的我就不再多敘述,
所以 register、static、global variable、constant 並不在此文探討範圍內。
----
※ 引述《amozartea (單車單車)》之銘言:
: 如題,這可能很少人問過
: 書上寫說區域變數其實都自動預設auto,
: 在編譯過程中並不會配置一塊記憶體空間,而是在程式執行時以堆疊的方式存放,
: 因此他是屬於動態的變數。
: ^^^^^^^^^^^^^^^^^^^^^^ 此段是出自洪維恩的書
這段省略了很多東西,洽巧初學者可能也不要知道會比較好,
因為可能會打擊學習程式的信心。
下面五行很重要,請記起來,沒記起來的話這篇文章你看不懂。
一個最重要、基本的觀念是:不論程式裡面的變數宣告成怎樣,
最終都會被放在記憶體裡面,而程式在執行時,這些記憶
體又被畫分為若干區段,其中你書本提到的是 stack (堆疊段)
與 heap (這個怎麼翻?) , 這兩個名詞以後請用英文寫出來,
我相信會比中文表達深切很多。
原文這段有四個字是重點:
編譯過程 ,指的是 編譯期
也就是上面這些動作是你在使用 dev-c++ / vc / gcc 等編譯器時,
就決定動作這些變數是要放 堆疊 段。
-----
引言 1
在編譯過程中並不會配置一塊記憶體空間,
而是在程式執行時以堆疊的方式存放,因此他是屬於動態的變數。
若照 C language 之定義,local variable 加 auto 時,其實有寫跟沒寫是一樣的。
也就是說
{
int i; // auto int i; 同義
int arr[3]={1,2,3}; // auto int arr[3]={1,2,3}; 同義
int *ptr=NULL; // auto int* ptr=NULL; 同義
}
上述三個變數,在編譯時,是由編譯器規劃其空間,最後是放在 stack 裡面,
而這類型的變數有個特性:
在程式執行的時候(稱執行期),這些變數可能會改變。
這是我猜測書本對於「動態」之解釋。
補註,這麼解釋真的不盡人意,因完全忽略了 static variable -
static int a=10; 這才是真正的 static variable,
還有一類型的變數,他們在執行的時候並不會改變他們的內含值 (value),
如 const variable ,像是這段 code
{
const char* txt="hello, world!!";
const double PI=3.1415926;
}
在程式執行txt 和 PI 從頭到尾都不可能會被改變(又是一個錯誤的思考:靜態),
它們不是被放在 stack 裡面,遺憾的也不是放在 heap 裡,
而是被放在其它的記憶體區段裡,這區段就叫 .rodata 區段,都是放唯讀的資料。
( 這也是那本書沒提到的部份 )
上面這段的重點只是:變數不宣告成 const 的話,是放在 stack ,
(雖這句話一點點問題..),完畢。
-----
: 但是又在動態記憶體章節上面寫說C++都是預設靜態什麼的 很讓人搞混
我猜書本上指的動態記憶體,大多指的是動態陣列 (雖然有時不一定要是陣列..)
截至目前為止,上敘其實只有提到 auto variable 是放在 stack 裡面。
接下來所有講「動態記憶體」,指的全部都是用 new / malloc 指令的東西,
但我很怕你會愈來愈亂,所以這部份重頭簡述至尾。
後半段必須探討到指標的東西,不熟的話再去複習一次。
一般而言,如果是寫
int arr[5] = {1,2,3,4,5};
這種方式宣告陣列的話,因為大小一開始就固定,在程式的 編譯期 就可以算出要多大,
且在 執行期 不可以改變陣列的大小,屬於靜態陣列。
( 還記得上一段有提到嗎?靜態陣列是放在 stack 裡面。)
但有時候,陣列要給多大必須在執行期的時候才可以知道,
比如說,先輸入班上有幾個人,再輸入每個人的成績,再做平均。
這時候沒辦法在 編譯期 時候就知道人數,此時會使用動態配置。
(如果扣掉被大多數人所垢病的 可變長度陣列,VLA, 作法時,只剩動態配置一途)
另,希望你沒忘記一件事:即使是指標,本身存的是「記憶體位址」,
故你常看到的動態配置的東西
{
int *a = NULL;
a = new int[10];
for(int i=0; i<10; ++i)
a[i] = i;
}
注意的是, a 本身是指標,它是在 編譯期 裡面就決定的東西,
是放在 stack 裡面。
而
a =
new int[10],
new int[10] 一開始先在 heap 上配置 10 個 int 大小,
最後把這 heap 的 "第一個位址值" 再傳回來給
a,
意思是如果配置的空間是 0x90000000 0x90000004 .....
最後 a 會存的是 0x90000000。
但這並不改變, a 本身是在 stack 上的事實,
會在 heap 上操作,只有這些動作:
*a=1 、 *(a+1)=10 、 a[1] = 10
因為是籍由指標 a ,去操作剛剛在 heap 上 new (這動作叫 allocate) 出來的記憶體。
所以呢?
int a[3]={1,2,3}; // 靜態記憶體陣列,放在 stack
int *a = new int[3]; // a 本身是指標,放在 stack;
// 而 a[i] 或 *(a+i) 本身放在 heap。
那放在 stack 和 heap 上有什麼差別?
速度 (access speed) 應是一樣的,
有幾個地方是顯然不同。
(a) 要用 heap 必須調用 new / malloc 相關指令 (在不考慮使用低階 api 情況下)
(b) 靜態陣列、一般變數 (扣除 const、static、global,但含 pointer),
是放在 stack 裡面,這在 編譯期 就可以由編譯器規劃好的東西;
而 heap 在編譯時要多大不知道,是在 執行期 時才由作業系統幫忙規劃。
(c) stack 可使用的空間範圍較小,而 heap 可使用的空間範圍較大;
所以,若陣列的元素個數很多,即使元素個數是固定的,也必須在 heap 上使用,
而不能放在 stack 裡面。意指:去試試 double x[2000000]; 好一點的 compiler
可能會有警告還是錯誤,這時候必須用 int *x=new int[2000000];
: ok 總之我目前的認知是一般的陣列是靜態宣告...
: (以下都是區域變數)
: int a; 跟 auto int a; 等價,而且這是動態
: int a[5]; 是靜態,,,應該吧?
這裡不要記動態、靜態,書本要表達的意思是,
int a; ---> 它是放在 stack 裡面 (用 動態 來形容就差了)
int a[5]; ---> 它是靜態的記憶體,因為不是用 new 運算子配置出來的,
也是放在 stack 裡面。
: 那假設我宣告如下(當然是區域):
: auto int a[5]; 這到底該算靜態還是動態? 已經試過編譯可以過...
完整的說法是:
因為它是 local auto variable,而不是 const variable (唯讀變數),
它的值可以被改變,放在 stack 裡面。
而陣列的大小固定為 5 ,在編譯期就可以知道的大小,是靜態陣列
也由於它不是唯讀,也是放在 stack 裡面。
: 如果是靜態那不是表示auto關鍵字在這裡沒用嗎@@?
: 如果是動態的話那跟
: int* a; a = new int[5];又有何不同
這點上面有說過了,細閱。
(結語 : 我可以說為什麼我不推這本書的原因了嗎? XD)
--
世界上有種,
將 不可能 轉換為 無限可能 的強大力量,
我稱它為 - 信念。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 180.177.69.239
→ tinlans:auto 之所以叫 auto,是因為不用手動控制它的生死。 01/19 19:47
→ tinlans:中文書用的詞彙,在講解這東西時很容易造成混亂是真的。 01/19 19:48
推 james732:推用心講解XD 01/19 21:12
→ angleevil:我只能說t大全部講解完了,實際上local variable預設 01/19 21:20
→ angleevil:是auto變數. 01/19 21:22
推 yudsx:推解釋詳細 只能說作者這樣寫很容易讓初學者誤會 01/19 22:45
→ LifePattern:第一次聽到用auto來說,就說是local會alloca在stack不 01/19 22:53
→ LifePattern:就OK了.. 01/19 22:53
→ tropical72:但 local 不一定會 allocate 在 stack 下啊 ~ 01/19 22:57
→ tropical72:好吧,或許我不該特別挑這問題出來講 XD 01/19 22:59
推 chunhsiang:可以問您 DLL載入的東西,他們的記憶體位置又會在哪裡? 01/19 23:44
→ chunhsiang:是OS幫忙載入,所以是在OS的另外的記憶體區段中? 01/19 23:46
推 amozartea:謝謝,請推薦我有寫這方面部份的書... 01/19 23:51
→ tropical72:dll問題扯太遠了,另開主題佳. 書:程式設計師的自我修養 01/19 23:52
推 amozartea:我讀過的都是語法和資料結構書等等都沒有講這方面QQ 01/19 23:53
→ diabloevagto:長知識! 01/20 00:01
→ LifePattern:我也推:程式設計師的自我修養! 01/20 00:56
→ LifePattern:local不會allocate在stack是指static var還是被優化? 01/20 01:00
→ tropical72:@LifePattern : static variable. const variable. 01/20 01:02
→ LifePattern:謝了,忘了const XD 01/20 01:19
推 LoveCheer:t大文 只有推了 01/20 07:07
推 s3748679:推用心+1 01/20 17:25
推 FOXSMALL:有學到!推一個 02/03 17:45