2014-12-06 45 views
10

我一直在寫一個小程序,其中我必須使用座標系統(x/y在二維數組中),並且正在考慮是否應該使用像array[x][y]這樣的索引,這對我來說似乎更自然,或者可以更好地匹配array[y][x]數組在內存中的表示方式。如果我保持一致並且只是命名問題,我相信這兩種方法都可以工作,但編寫大型程序時慣例如何?在C中用x/y座標索引二維數組有什麼約定?

+1

只要你一致,它應該沒有關係,但有兩種情況我可以想到'array [y] [x]'會在哪裏幫助。 1)一個字符串數組,你可能想要處理1-d'array [y]'。 2)一個圖像陣列,您可能想要掃描一條光柵線。對於(x ...)',我更喜歡'嵌套處理循環的數組[y] [x]'。 – 2014-12-06 23:47:35

+0

數組是行優先的,所以'a [0] [1]'是'a [0] [0]'之後的下一個內存位置。選擇適合您程序的方式。 – 2014-12-07 01:08:22

+2

。語言的自然更多是它['y] [x]'使用 – chux 2014-12-07 04:51:10

回答

7

在我的領域(圖像處理)[y][x]約定更爲常見。無論你做什麼,都要保持一致並將其記錄在案。

2

您還應該考慮您將對這些陣列做什麼,以及這是否對時間至關重要。

正如在評論中提到的:元素a[r][c+1]就在a[r][c]的旁邊。這個事實在迭代更大的數組時可能會對性能產生相當大的影響。正確的遍歷順序將導致緩存行被完全利用:當一個數組索引被訪問時,它被認爲是「可能的」,之後,下一個索引將被訪問,並且整個內存塊將被加載到緩存。如果您之後訪問完全不同的內存位置(即下一行中的內存位置),則會浪費此緩存帶寬。

如果可能,您應該嘗試使用適合實際內存佈局的遍歷順序。

(當然,這是很多關於「約定」和「習慣」:當寫像a[row][col]數組訪問,這通常解釋爲數組訪問a[y][x],由於x軸的慣例是水平的和y軸是垂直...)

下面是展示一個「錯誤的」遍歷順序的潛在性能影響的一個小例子:如果

#include <stdlib.h> 
#include <stdio.h> 
#include <time.h> 

float computeSumRowMajor(float **array, int rows, int cols) 
{ 
    float sum = 0; 
    for (int r=0; r<rows; r++) 
    { 
     for (int c=0; c<cols; c++) 
     { 
      sum += array[r][c]; 
     } 
    } 
    return sum; 
} 

float computeSumColMajor(float **array, int rows, int cols) 
{ 
    float sum = 0; 
    for (int c=0; c<cols; c++) 
    { 
     for (int r=0; r<rows; r++) 
     { 
      sum += array[r][c]; 
     } 
    } 
    return sum; 
} 


int main() 
{ 
    int rows = 5000; 
    int cols = 5000; 
    float **array = (float**)malloc(rows*sizeof(float*)); 
    for (int r=0; r<rows; r++) 
    { 
     array[r] = (float*)malloc(cols*sizeof(float)); 
     for (int c=0; c<cols; c++) 
     { 
      array[r][c] = 0.01f; 
     } 
    } 

    clock_t start, end; 

    start = clock(); 
    float sumRowMajor = 0; 
    for (int i=0; i<10; i++) 
    { 
     sumRowMajor += computeSumRowMajor(array, rows, cols); 
    } 
    end = clock(); 
    double timeRowMajor = ((double) (end - start))/CLOCKS_PER_SEC;  

    start = clock(); 
    float sumColMajor = 0; 
    for (int i=0; i<10; i++) 
    { 
     sumColMajor += computeSumColMajor(array, rows, cols); 
    } 
    end = clock(); 
    double timeColMajor = ((double) (end - start))/CLOCKS_PER_SEC;  

    printf("Row major %f, result %f\n", timeRowMajor, sumRowMajor); 
    printf("Col major %f, result %f\n", timeColMajor, sumColMajor); 
    return 0; 
} 

(道歉我違反了一些最佳實踐在這裏,我是usua lly一個Java人......)

對我來說,行主要訪問幾乎比列主要訪問快一個數量級。當然,確切的數字將會是沉重取決於目標系統,但所有目標的一般問題應該是相同的。