malloc分配給指標空間與之間建立陣列的區別

2021-07-01 18:33:55 字數 3951 閱讀 6414

首先回答你的問題:嚴格的說不等於陣列,但是可以認為它是個陣列一樣的使用而不產生任何問題。

不過既然這樣,那它應該算是個陣列吧。

所以,一般我們都用「動態陣列」這種名字來稱呼這種東西。

要講清楚這個東西,涉及到malloc函式,指標型別和「[ ]」下標運算。

*****=分割線[0]*****=

malloc是c的標準庫函式之一,用來分配動態記憶體。

一般來說,由c/c++編譯的程式會在執行的時候在記憶體中占用一些空間,它們分為以下幾個部分:

1.二進位制**區 不必過多解釋了,就是放二進位制**的地方。

2.常量區 存放文字字串和常量

3.靜態儲存區 存放靜態和全域性變數

4.堆空間 動態記憶體區,程式設計師可控制分配和釋放的區域。

5.棧空間 由編譯器分配記憶體用於儲存函式引數和普通變數。

malloc能操作的是程式中的堆空間,而普通的陣列則是存放在棧空間裡面的。

由於作業系統對這兩部分的記憶體管理模式差別很大,所以我們一般認為是不同的。

堆空間是系統記憶體中的可用區域,和普遍意義上的「堆(heap)」不同,基本上可以看作是由空閒記憶體組成的大鍊錶。

嘛,作業系統怎麼處理這東西不管了,反正你就可以認為堆空間是可用記憶體裡的一片連續區域。

malloc函式的作用就是從這一片記憶體中劃出一塊空間來。你可以認為是malloc從記憶體中找到了一片可以安全存放資料的可用空間,這樣你的資料就可以放在這片空間裡面。這片空間的大小是你自己指定的。通過malloc(位元組數)這樣簡單的方法。

為了找到這片空間,malloc函式會告訴你這片空間開頭的位址,你可以把它賦值給乙個變數存放起來。

這樣我們就知道申請到的這片記憶體的首位址(malloc返回)和大小(程式設計師指定)了。

*****=分割線[1]*****=

這部分先放著,我們來看指標型別。

c語言的指標也有型別,但是指標總是記憶體位址,是乙個(32位/64位)二進位制整數,長度也好大小也好都是確定的,理應一種型別就夠了。那麼,指標型別的作用是什麼呢?其實指標型別就是用於判斷指標所指向的資料的型別。

不得不說這是乙個非常天才的設計。

指標裡存放著的是乙個位址,它能找到乙個記憶體單元(複雜的東西不說了,作業系統都給你做了,你就認為是某乙個位元組就好。這個括號內部的東西寫給某些較真的人看,實際上並不存在一種叫做記憶體單元的東西。),但是資料有長有短,資料們有些存在1個記憶體單元裡面,有些存在多個記憶體單元裡面。

指標是為了指向乙個資料,那麼,用什麼方法可以知道這個指標想要的,到底是幾個記憶體單元裡的資料呢?

c語言裡用了一種十分巧妙的設計——指標型別。乙個指標指向乙個位元組位址,這個指標的型別所代表的資料結構是8個位元組,那麼我們就把這8個位元組裡面的東西都讀出來,作為這個指標所指向的資料的值。

舉個栗子:比如說從位址是1000開始的記憶體是以下的一片樣子:

00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000

00001001 00001010 00001011 00001100 00001101 00001110 00001111 00010000

然後我有個指標a,它的值是1000。

如果這個指標是int *a。當我用*a去訪問資料的時候,就會返回【00000001 00000010 00000011 00000100】

這些資料。

但是如果這個指標是double *a。當我用*a去訪問資料,返回的就是【00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000】這些資料了。

不過這個指標值可是沒有變化的,變化的只是指標型別而已。

在回到原來那個問題,我們現在用malloc取得了一片空間,但是要讓編譯器知道其中每個資料佔多少空間,就是由指標型別來確定了。

這就是為什麼malloc函式在賦值給指標之前要有乙個強制型別轉換的原因。否則void *型別一般應該是讀不出資料的。

(此括號再次寫給較真的人們,直接使用void *指標是未定義行為,未定義行為是編譯器說了算的,它不想給你返回值就不給你返回值了。不過我們現在的編譯器都比較好心,一般是會給你返回1個位元組的值的,用起來大概就和char *乙個感覺。)

比如說a=(int *)malloc(10240);

這一段**就取得了10240個位元組(10kb)的可用空間,然後把首位址告訴了變數a。然後我打算存放的資料是整型的,一次要求程式在這段記憶體裡面讀4個位元組返回。所以我使用了(int *)來確定指標型別。

這樣,當我們使用*a時,就可以訪問到從a指向的位址開始的4個位元組裡面的資料了。

*****=分割線[3]*****=

可是我們申請了10240個位元組呢。。。能存2560個整型變數呢。只能訪問前4個位元組有什麼用?難道要每4個位元組申請一次?

怎麼訪問後面的記憶體空間呢?

我們可以移動指標,比如把指標往後移4個位元組。這樣就能訪問到這片區域裡面的第2個整型變數了。

(注意,如果是int *型別的指標a,把a往後移4個位元組的操作是a=a+1,千萬不要搞成a=a+4了。為什麼這麼做原因後面再講。)/*補充[0]*/

可是還是很麻煩,如果我要一次一次的遍歷這片區域,或者同時訪問裡面的第12個和第450個變數。那麼程式裡就必然存在2個或2個以上的指標。

為了簡化訪問方法,c語言使用了一種簡單的對指標運算——[ ]下標運算。

[ ]運算子是c語言幾乎最高優先順序的運算子。[ ]運算子需要兩個運算元,乙個指標型別,乙個整數。/*補充[1]*/

標準的寫法是這樣的:

。這樣編譯器會返回 *(a+i) 的值。

這樣做的話相當於乙個十分好用的臨時指標的移動。

如果我要訪問第12個變數只需要寫a[11]就好了。編譯器會理解這個運算的規則,自動的把a指標進行一次以下的操作:

int *temp;temp=a+11;return *temp;

嗯,大概就是這個樣子。

*****=分割線[4]*****=

該回到正題了。因為c語言為我們提供了這樣的方法,使得我們申請到的一片記憶體連續區域,可以使用這樣的方法,像陣列一樣的訪問到。

不過陣列明顯更加簡單。int a[2560]同樣是申請一片10kb的空間,這部分空間存放在棧空間裡面。記憶體位址也是完全連續的。

值得注意的是,陣列名a其實被宣告為常量指標const int *,它同樣儲存的是陣列的首位址。

(本括號寫給較真的人看,c/c++自動把陣列型別隱式宣告為常量指標,這個動作其實更類似於隱式轉換,而不是直接宣告那個指標。)

然後這麼說來[ ]。操作符在普通陣列上和用malloc生成的動態陣列上的操作是完全一樣的,都是類似於*(a+i)的操作。

所以從這層意義上來講,用malloc分配的空間本質上和陣列沒什麼區別。它們主要的區別還

是存放的記憶體區域在作業系統對記憶體管理上的區別

。不過這層區別也不小,所以一般不把malloc分配的空間等同為陣列,而是用「動態陣列」來區別的對待它。

最重要的區別也許就是使用完了

以後記著用free釋放掉。

*****=分割線[5]=完,下面是補充內容*****

補充[0]:作業系統給你分配的記憶體,一般只有棧空間是連續的。比如你申請乙個10kb的堆空間區域,其實很少能申請到全連續的一段記憶體。一般都是中間會有斷開的方式。

作業系統是用

類似於鍊錶的方式

來管理這些分片的記憶體空間的。

所以說,雖然指標本質就是個整數,但是指標的運算不是簡單的改變這個整數,而是指向下一儲存區這樣的意思。

因為如果是讓你簡單的改變這個整數,很可能這個指標指向的就是記憶體中其他程式的區域了。甚至是系統重要的**區域。這是絕對不允許的,所以編譯器才會採用這樣的定義。即給int *a定義的指標a進行a++這種運算的過程實際上相當於:1.返回a的當前值 2.找到a當前的記憶體區域 3.在鍊錶中查詢下4個位元組的存放區域,並把首位址賦值給a。

補充[1]:事實上ansi c並沒有定義兩個運算元的順序。指標[整數]只是一種常用寫法。寫成整數[指標]也未嘗不可。

定義陣列int a[20]之後,使用5[a]一樣可以訪問到這個陣列裡第6個整型變數的值。

Oracle 建立表空間並分配給使用者

rem 建立臨時表空間 create temporary tablespace pksniq temp tempfile d pksniq temp.dbf size 32m autoextend on next 32m extent management local rem 設定表空間的區管理為本...

配置pod與容器 將記憶體資源分配給容器和Pod

本文介紹如何為容器分配記憶體請求和記憶體限制。保證容器具有其請求的記憶體量,但不允許使用比其限制更多的記憶體。第一步 建立命名空間 在本例中建立命名空間,與集群中其餘的資源部分隔離 kubectl create namespace mem example第二步 指定記憶體請求和記憶體限制 要為容器指...

指標為NULL與空間malloc(0)的解釋

char ptr if ptr char malloc 0 null puts got a null pointer else puts got a valid pointer 上面程式在vc6.0下輸出結果是 got a valid pointer 請問指標為null時指向 分配的空間為0時又指向...