2010-01-29 31 views
6

我有這個循環給seg。故障。如何將指針視爲多數組?

s->c = malloc(width * height * sizeof(double)); 
    if (s->c == NULL) { puts("malloc failed"); exit(1); } 

    for (int n = 0; n < width; n++) { 
    for (int m = 0; m < height; m++) { 

     d = (&s->c)[m][n]; 

     printf("d %f\n", d); 
     printf("m %i\n", m); 
     printf("n %i\n", n); 

    } 
    } 

內部S-> c是:

double* c; 

當被執行時,它只是輸出:

d 27.000000 
m 0 
n 0 

然後SEG。故障。

它工作時,我把s-> c作爲一維數組,但我真的很想把它當作二維數組。

這是可能的,當c指針在一個結構?

如果是這樣,是(&s->c)[m][n]那麼訪問元素的正確方法是?

桑德拉

+2

你可以給我們更多的代碼,特別是分配。 – tur1ng 2010-01-29 13:03:16

+0

c如何分配? – 3lectrologos 2010-01-29 13:03:49

+0

現在添加了如何分配c。 – 2010-01-29 13:08:35

回答

5

問題是編譯器不知道矩陣的尺寸。

當你有:double tab[m][n]您可以訪問該元素tab[row][col]*(tab + (row * n) + col)

你的情況,你只有double *tab;可以被視爲指針元素tab[0][0]與基體尺寸沒有信息和編譯器可以不計算正確的地址。

你可以自己計算地址(例如使用一個宏),但會失去很好的​​語法。

我很驚訝它編譯。您應該至少收到一條關於隱式地將double賦值給指針的警告。

0

如果你想分配S-> C作爲一維數組,那麼你可以定義一個宏,沒有工作適合你(但你需要知道的第二個維度):

#define AR(M, X, Y) ((M)[(Y) + dimy * (X)]) 
+4

但在這個C++時代,我們嘗試使用(內聯)函數,而不是宏的。 – xtofl 2010-01-29 13:15:36

+0

我只是不想將維度也作爲參數傳遞(以便宏類似於c [m] [n]表達式)。 – 3lectrologos 2010-01-29 13:21:49

4

我很驚訝它甚至編譯。顯然cdouble*,所以(&s->c)[m]是第m個double。現在,double沒有operator[],所以我看不到(&s->c)[m][n]中的[n]部分是合法的。

大概你已經聲明c的方式不同。有不同的解決方案:指向指針的指針,指向雙精度數組的指針,指向雙精度指針的數組等等。如果分配與聲明匹配,所有可能的工作。在你的情況下,分配將不符合聲明。

+3

我覺得's-> c'是'double *',所以'&s-> c'是'double **',但是'(&s-> c)[1]'是垃圾,所以'( &s-> c)[1] [0]'觸發故障。 – dave4420 2010-01-29 13:16:43

+0

「一個指向雙精度數組的指針」看起來如何? – 2010-01-29 13:19:17

+0

double * values []; – tur1ng 2010-01-29 13:33:12

2

訪問數組元素的正確方法是

d = s->c[m * width + n]; 

是你通過將其視爲一維數組是什麼意思?

+0

是的,當我這樣做,它的工作。但我不明白爲什麼它會崩潰,當我把它當作二維數組處理時。 – 2010-01-29 13:16:12

+0

由於數組下標是根據指針算術定義的。對於你的代碼,這意味着'(s-> c)[m] [n]'被評估爲'*(*(s-> c + m)+ n)'。這意味着'*(s-> c + m)'預計會被評估爲*指針*類型。然而,由於's-> c'是'double *'類型,'*(s-> c + m)'計算爲double值。試圖將這個雙重值作爲指針處理會導致seg錯誤。 – 2010-01-29 16:47:09

1

訪問使用

也許通過在線功能,避免意外行爲的元素。

編譯器不知道您想要的2D數組的寬度。它可能會解釋(& s-> c)[m] [n]爲s-> c [m + n],或者是完全不同的東西。

1

簡答:你不能把它當作二維數組,至少不是你期望的方式。

之所以寫

(&s->c)[m][n] 

不起作用,可以如下所示。假設s->c的地址爲0x00080004,s->c指向的動態分配內存地址爲0x00001000。

  1. 表達式(&s->c)[m][n]被評估爲*(*(&s->c + m) + n);
  2. 表達式&s->c評估爲0x00080004;
  3. 表達式(&s->c + m)評估爲0x00080004+m;
  4. 表達式*(&s->c + m)的計算結果爲0x00080004+m指向的值。如果m爲0,那麼0x00080004+m指向0x00001000,這是您動態分配的內存的地址(*(&x) == x)。如果m是任何其他值,則0x00080004+m隨機指向某處;
  5. 表達式(*(&s->c + m) + n)的計算結果與0x00080004+m的計算結果相差n。如果m爲0,則值爲0x00001000+n,或者是到您的動態分配內存的偏移量。如果m不是0,那麼該值是隨機的;
  6. 表達式*(*(&s->c) + m) + n)試圖取消上述值。如果m爲0,那麼結果是動態分配數組中元素的值。如果m不是0,那麼結果是...別的東西。在你的情況下,一個段錯誤。

如果您要動態分配一個二維數組,你必須使用一個指針的指針和步驟分配它,就像這樣:

struct { 
    ... 
    double **c; 
    ... 
} *s; 
... 
/** 
* Notes: type of s->c is double ** 
*   type of *(s->c) and s->c[i] is double * 
*   type of *(s->c[i]) and s->c[i][j] is double 
*/ 
s->c = malloc(sizeof *(s->c) * rows); 
if (s->c) 
{ 
    for (i = 0; i < rows; i++) 
    { 
    s->c[i] = malloc(sizeof *(s->c[i]) * columns); 
    if (s->c[i]) 
    { 
     // initialize s->c[i][0] through s->c[i][columns-1] 
    } 
    } 
} 
0

我很驚訝,沒有人提到boost::multi_array_ref

#include <iostream> 
#include <boost/multi_array.hpp> 

int main() 
{ 
    int rows = 4, cols = 3; 

    // Allocate one big block of contiguous data for entire multi-array 
    double* arrayData = new double[rows*cols]; 

    if (arrayData) 
    { 
     boost::multi_array_ref<double, 2> 
      arrayRef(arrayData, boost::extents[rows][cols]); 
     for (int row = 0; row < rows; ++row) 
     { 
      for (int col = 0; col < cols; ++col) 
      { 
       arrayRef[row][col] = row*cols + col; 
       std::cout << arrayRef[row][col] << " "; 
      } 
      std::cout << std::endl; 
     } 
    } 
    delete [] arrayData; 
} 

你也可以使用boost :: multi_array中,並動態調整大小:

boost::multi_array_ref<double, 2> marray; 
marray.resize(boost::extents[rows][cols]);