C 二維陣列還是一維陣列?

2022-07-04 08:48:14 字數 4189 閱讀 4282

記得剛學習c++那會這個問題曾困擾過我,後來慢慢形成了不管什麼時候都用一維陣列的習慣,再後來知道了在一維陣列中提出首列元素位址進行二維呼叫的辦法。可從來沒有細想過這個問題,最近自己寫了點**測試下,雖然還是有些不明就裡,不過結果挺有意思。

為了避免編譯器優化過度,用的是寫操作,int,測試分為不同大小的空間,同樣大小空間不同的行和列數。分別記錄逐行寫入,逐列寫入,按間隔寫入,空間申請和釋放的時間。

測試**

一維陣列的申請和釋放

1

//create

2int *m = new

int[n_row *n_col];34

//free

5 delete m;

二維陣列的申請和釋放

1

//create

2int **m = new

int*[n_row];

3for ( int i = 0; i < n_row; ++i )

4 m[i] = new

int[n_col];56

//free

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

8delete m[i];

9 delete m;

逐行寫入

1

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

2

8 }

逐列寫入

1

for ( int j = 0; j < n_col; ++j )

2

8 }

按間隔寫入

1

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

210 }

不是很確定這種測試是否很合理,不過大體上能體現我要測的東西了。需要注意的是逐行寫入中為了簡便我用的是寫入乙個叫answer的變數,其實情況應該更泛化,否則用memset或者std::fill也許會更快?逐列寫入的**本科課程級別的典型反面**例子,這裡也僅僅是為了測試。

僅僅從編譯的角度來看主要的差別在下面兩句:

1 matrix[i * n_col + j] =answer;

2 matrix[i][j] = answer;

來看一下對應的彙編**:

1

;matrix[i * n_col + j] = answer;

2mov

edx, dword ptr _i$3[ebp]

3imul

edx, dword ptr _n_col$[ebp]

4add

edx, dword ptr _j$2[ebp]

5mov

eax, dword ptr _matrix$[ebp]

6mov

ecx, dword ptr _answer$[ebp]

7mov dword ptr [eax+edx*4], ecx

1

;matrix[i][j] = answer;

2mov

ecx, dword ptr _i$4[ebp]

3mov

edx, dword ptr _matrix$[ebp]

4mov eax, dword ptr [edx+ecx*4]5

movecx, dword ptr _j$3[ebp]

6mov

edx, dword ptr _answer$[ebp]

7mov dword ptr [eax+ecx*4], edx

都是6條指令,體系學得不好,所以也看不出哪個更快。這裡用的是visual studio編譯,因為本人gcc用得不熟,不知道怎麼生成這麼直觀的彙編和c++對應,效率上而言linux下還是比windows高一些,不過為了統一,之後的測試也基於windows。當然上面的是沒有優化的編譯,如果開了優化(vs /o2),彙編指令大概也都是4、5條的樣子,因為/o2優化後的彙編**結構不是很直觀,這裡就不貼了。(另一方面也是由於我的彙編水平很弱,看不出什麼)

除了直接使用一維和二維陣列,也可以對一維陣列進行二維索引,方法是把一維陣列中所有對應第一列的元素的位址單獨作為乙個指標陣列,這樣本質上還是一維陣列,但是實現了形式上的二維陣列呼叫,這種辦法空間申請的**如下:

1

//create

2int **m = new

int*[n_row];

3int *block = new

int[n_row *n_col];

4for ( int i = 0; i < n_row; ++i )

5 m[i] = &block[i *n_col];

6return m;

釋放的**和二維陣列相同。

用一維陣列模擬二維呼叫的優點是既保證了記憶體空間的連續性,又保持了二維呼叫的**易維護的優點。不過需要注意的是,由於是二維索引,彙編**和二維陣列還是一樣的。

測試結果

執行上面的**,在不同行數和列數下,迴圈執行取平均值,結果如下:

記憶體的申請和釋放

逐行訪問

逐列訪問

按間隔訪問

分析

記憶體的連續性:一維陣列顯然有著比二維陣列更好的連續性,我忘了以前是在哪看到的乙個形象的字元畫說明一維陣列和二維陣列的區別,大概是下面這樣子:

一維陣列:

┌--┬--┬--┬--┬- 

| | | | | ...

└--┴--┴--┴--┴-

二維陣列:

┌--┬--┬--┬--┬- 

| | | | | ...

└--┴--┴--┴--┴-

| | |

| | v

| | ┌--┬--┬--┬-

| | | | | | ...

| | └--┴--┴--┴-

| v

| ┌--┬--┬--┬--┬-

| | | | | | ...

| └--┴--┴--┴--┴-

v ┌--┬--┬--┬--┬--┬-

| | | | | | ...

└--┴--┴--┴--┴--┴-

快取命中率:快取是sram,記憶體是dram,效率差很多,所以如果能提高快取中的命中率,效率能提高很多。其實這和上一條其實也有關聯,顯然連續的記憶體命中率會高,不過如果申請的記憶體空間非常大那具體問題得具體分析了。

指令執行速度:由於早年體系沒學好,所以我也不知道這條有多大影響,另外現在的電腦都是多核的,作為不搞多核算法的人,不太懂會有多大影響。

對照結果可以看到基本上而言一維陣列的效率完爆二維陣列,尤其是記憶體申請和小記憶體訪問的情況,總體而言效率上一維陣列》一維陣列的二維引用》二維陣列。不過也有比較有意思的發現:1) 逐行訪問的時候,在開闢記憶體空間小的時候一維陣列二維索引效率高於二維陣列,而大記憶體情況下卻變慢了。2) 逐列訪問基本符合預期,一維陣列和一維陣列二維索引效率接近,二維索引效率略低,但是都優於二維陣列。3) 按間隔訪問的時候一維陣列大幅快於逐行訪問,不太懂這是為什麼,是否我電腦是多核的影響?還是說vs的o2編譯的作用?

純屬蛋疼的測試,也相當不嚴謹,希望有體系知識比較豐富的大拿指點一二。

陣列(一維陣列 二維陣列)

陣列概述 c 陣列從零開始建立索引,即陣列索引從零開始。c 中陣列的工作方式與在大多數其他流行語言中的工作方式類似。但還有一些差異應引起注意。這些其實和泛型有些類似,陣列的操作沒有泛型方便,但是效能卻不是泛型所能比擬的 宣告陣列時,方括號 必須跟在型別後面,而不是識別符號後面。在c 中,將方括號放在...

c 一維陣列,二維陣列,多維陣列。

陣列就是給乙個變數定義多個字元,可以是string也可以是int。或者說是一組變數。可以更加方便的操作大量資料。陣列的定義 1 陣列裡面的內容必須是同一型別 2 資料必須有長度限制 一維陣列 一 資料型別 變數名 new 資料型別 長度 陣列定義 string a new string 這裡寫陣列包...

Javascript 陣列 一維陣列 二維陣列

建立陣列語法 var myarray new array 我們建立陣列的同時,還可以為陣列指定長度,長度可任意指定。var myarray new array 8 建立陣列,儲存8個資料。我們還可以用簡單的方法建立陣列和賦值 第一種方法 var myarray new array 66,80,90,...