用 C 實現乙個變長陣列

2021-06-29 05:28:26 字數 1351 閱讀 3801

我想用 c++ 的人都用過 std::vector 。它是乙個可變長的陣列,在很多時候都比 c 固有的定長陣列要靈活。

c 裡沒有這樣的標準化設施,但是寫軟體的人通常都會實現乙個。正所謂,不厭其煩的重造輪子 :d 。這裡我們不討論造輪子的好壞問題,直接討論下實現這麼個東西的一點小技巧吧。總是固執於用誰做的輪子的問題,眼光就太短淺了。

一般的 vector 的實現,需要記錄三個資料:資料空間的位址,空間大小,陣列裡已存在的元素個數。也可能是這三個元素的變體。比如在 msvc 的 stl 實現中,vector 儲存的是三個 iterator:陣列頭指標、最後乙個元素的指標、分配出來的全部空間的末尾指標。

msvc 的 vector 的分配策略是這樣的。一開始不於分配空間,當第乙個元素被 push back 後,空間擴充套件。通常,擴充套件的請求至少要滿足請求擴充套件的尺寸,或者是講已有的空間容量翻倍。比如,當你已經有 16 個單元的陣列空間時,如果再申請 3 個,vector 會自己擴充套件到 32 個單元;若你一次要求從 16 個單元擴充套件到 40 個單元(超過 16*2),那麼就直接擴充套件到 40 。

記得 stlport 也是類似的策略吧,實現的可能稍有不同。

正是如此,我們在用 vector 的時候要比較小心。如有可能,最好先 reserve 出需要的空間,而不是乙個個的 push back 。否則,如果你從 0 個元素,push back 100 次,其空間會重新分配 8 次(1、2、4、8、16、32、64、128)。btw, 如果你經常這樣做,最好實現乙個優秀的 allocator 。imho ,msvc 的 stl 實現並不比 stlport 差,大多數效能差別都是因為 msvc 的 stl 實現未能給出乙個通用的,優化過的分配器而已。(實現乙個好的記憶體分配器,對於大的 c++ 軟體專案,都值得去做)

今天想說的並不是怎麼優化這個策略。是我這幾天在寫**時發現,如果你遵照空間加倍這個策略來運作,其實並不需要三個變數來維持 vector 結構,兩個就夠了。那個表識容量大小的變數是多餘的。:d

下面是段示範**:

struct

vector

;void

vector_expand

(struct vector *v,

int s)

}

利用二進位制邏輯運算的性質,我們只需要把新的尺寸和老的尺寸異或,再和老的尺寸比較,就可以知道,新的尺寸的二進位制最高是 1 的那一位的位置是否大於老的尺寸。然後分配新尺寸的兩倍,空間是綽綽有餘的。

當然,如果你希望空間分配的恰到好處(2^n -1 ),可以稍微寫的繁瑣一點,以下**在 32bit 機器上,可以把乙個數字從它的二進位制為 1 的最高位到最低位都填成 1 。

unsigned

foo(

unsigned a)

用vector實現乙個變長陣列

所謂陣列,有這樣的性質 c語言中的陣列,一旦長度定義,就不能改變。有時候需要動態增加陣列長度,而且想保留上述性質,這時候就可以用vector。vector模擬了c語言中陣列的操作,比如取值,下標越界未定義等。最重要的,它支援size 和resize 方法,可以獲得陣列長度,以及擴充套件陣列長度。這樣...

專題 如何定義乙個可變長陣列?

與本文章無關的背景 就是想吐吐槽嘛 昨天刷codeup的時候,碰到字串的問題,就頭皮發麻,然後今天早上吃 老譚酸菜牛肉麵 譚浩強版c程式設計 的時候,翻到對於可變長陣列定義的方法。分割線 版權歸老譚擁有 首先,看一下像我這樣的小菜鳥一開始會這樣定義 int n scanf d n int a n 顯...

用C 實現乙個日期類

最近在複習c 的時候發現日期類是乙個非常有用的類,在現實中是非常實用的 雖然我不知道為什麼這麼實用的類,庫里沒有 以下是我自己實現的日期類的 因為大部分都是運算子的過載,所以理解起來應該並不難 include include using namespace std class date date c...