C 儲存方式

2021-05-26 15:29:00 字數 2576 閱讀 7202

今天,莫名其妙地「奮奮」。

看著一本c++的時候,突然想到,是不是可以用陣列越界來**一下,c++的儲存方式呢?由於書頁上的內容太多。就簡單地寫寫吧。

int main()

const int size = 4;

float a[size] = ;

for (int i=0; i<7; i++)

cout << "\ta[" << i << "] = " << a[i] << endl;

system("pause");

return 0;

//這裡不報錯吧?很犀利。就是要用這個不報錯的bug(c++的硬傷)來深入一下這個強大的東西。想知道他是怎麼儲存的。

有一則例子,應該是很早以前的編譯器寫的。那個時候c++的確實會像我寫那樣輸出。

int main()

float a = ;

float x = 11.1;

cout << "x = " << x << endl;

a[3] = 88.8;

cout << "x = " << x << endl;

system("puase");

return 0;

輸出是什麼呢?

x = 11.1

x = 88.8

此時很驚訝。a[3]的非法使用,本身是不報錯的,可是它修改了另乙個變數的資料x!

要是在大型程式,幾千萬行**中,怎麼辦?這種把頭皮擦破都想不出來。因為它能通過編譯。

不過,有經驗的人都會主動去查野指標、陣列越界。這個是很好的經驗,確實能夠修復bug,也能夠讓測試人員順利地驗證通過。

原因就會表明:陣列越界、野指標。具體操作和記憶體的使用並不太清楚。這個也是我為了想知道,並且在知道後興奮地寫部落格的原因。

我相信,現在興奮的時候,會主動地寫,以後沒了這個激情,見怪不怪就不會寫了。為了儲存這一刻青澀的激動。並且拋棄上面的老古董。

來看看新的**。和上面的類似。不過上面的**在當前很多規範的編譯器已經克服掉了。那麼就看看它怎麼克服的。

#include

using namespace std;

int main()

;cout << "x = " << x << endl;

a[7] = 88.8;

cout << "x = " << x << endl;

cout << "a的位址 " << &a << endl;

cout << "x的位址 " << &x << endl;

cout << "float的大小 " << sizeof(float) << endl;

system("pause");

return 0;

} //這裡a[7]就是x!

輸出:x = 11.1

x = 88.8

a的位址 0x22ff50

x的位址 0x22ff6c

float的大小 4

這個時候,應該很激動地來計算&a與&x的公式了: &x = &a + 2*3*sizeof(float) + 1。

這個公式經典了!

也就是說,當前的編譯器是怎麼在防止陣列越界的。在開闢的首位址做始點,然後2倍的陣列空間長,這就是陣列的記憶體空間。

那麼下乙個變數是在**呢?很明顯,是這個陣列記憶體空間後的第一位。

這個問題清楚了。激動了。那麼就來不激動的了:

我的概念裡,有靜態儲存方式,這個要區別static。因為這個是記憶體角度,或者說類似讀計算機組成原理來的概念,被我自己的語言總結成的。

這一點先說明好了。貼下面的體會就好理解了。

1 這裡揭示了乙個很重要的資訊:c++是如何儲存數值的。從這裡測試例子來看很明顯,可以很直觀地解釋:固定的變數是可以確定空間大小的,包括各種內建型別、類型別等的物件,他們按作用域被封裝在一塊記憶體區域,這個記憶體區域中,各個變數的空間是連續挨著的,這裡通過陣列可以越界來測試這種儲存方式。這裡的變數都是靜態儲存。

2 這個測試要注意:只能測試靜態儲存方式。因為這種方式的型別是確定的。容易把握後邊的資料怎麼翻譯的問題。如果方式不確定,不能確定翻譯需要的空間定長,或者不匹配,都會讀出不同結果的值。這個值對自己的測試目的和把握來說,是不可控的。

3 通過陣列可以越界這一特點,來測試c++的記憶體管理。可以確定靜態儲存的有兩種變數:區域性變數和全域性變數。static和auto。static是另外一片連續的儲存空間,按宣告順序來分配空間。這篇區域叫靜態儲存區。這個靜態和儲存方式的靜態在這裡是必須要區別的(不做解釋,理解提公升了就懂了我的意思了,這裡強調是方式,是跟物理記憶體有關的實現,而不是上層的概念)。另外關於動態的,是用堆來實現。程式中無法在編譯階段確定大小的,需要等待執行時資料,在執行過程中開闢空間。而普通的能在編譯階段確定的也是按作用域來分段,按宣告順序來定義的靜態儲存方式。

4 經測試,我發現當前的做法是資料以2倍+1的空間分界,下乙個變數以此界開始分配。

//這一段是我讀的過程中寫的筆記,雖然總結得不太清楚,也不大好理解。但是確實編譯器是這樣子的。要梳理總結比較麻煩,就貼這裡吧。

至於那個所謂的堆,其實是資料結構裡,我記得那段malloc的演算法**。嚴蔚敏那本書很枯澀,但是治學就是這麼嚴謹了。對她來說,這已經她盡了很大努力把概念通俗了。

我說的堆,其實也就是那段**的實現方式(畢竟我弄不出c++編譯器的真正源**)。

C 動態儲存方式與靜態儲存方式

如果從變數值存在的時間 即生存期 來分,可將程式中的變數分為 動態儲存方式和靜態儲存方式。它們所占用的儲存空間區域不同。區 存放可執行程式的程式 靜態儲存區 存放靜態變數和全域性變數。棧區 stack 存放動態區域性變數 堆區 heap 存放new和 malloc 申請的動態記憶體。棧區和堆區統稱為...

C變數的儲存方式

變數可以分為全域性變數 靜態全域性變數 靜態區域性變數和區域性變數 按儲存區域分 全域性變數 靜態全域性變數和靜態區域性變數都存放在記憶體的全域性資料區,區域性變數存放在記憶體的棧區 按作用域分 全域性變數在整個工程檔案內都有效 靜態全域性變數只在定義它的檔案內有效 靜態區域性變數只在定義它的函式內...

C 小數的儲存方式

在c c 中float是32位的,double是64位的,兩者在記憶體中的儲存方式和能夠表示的精度均不同,目前c c 編譯器標準都遵照ieee制定的浮點數表示法來進行float,double運算。無論是float還是double,在記憶體中的儲存主要分成三部分,分別是 1 符號位 sign 0代表正...