2011-01-18 10 views
2

私はC(< 1週間)の完全なnoobです。私は他の言語でのプログラミングに精通していますが、私はそれに取り組む方法を理解しようとしています。最初の目標として、私はマトリックス上でガウス減少を行う関数を書こうと思っていました。アルゴリズムに問題はありませんが、行列を表現する方法はわかりません。わかりやすくするため、floatのエントリを使用しているとします。マトリックスの構造

最初NAIFの方法は、アプリオリ(もちろん私はなりたい寸法を知らなくても、あなたが引数として、このようなオブジェクトを渡すことができないことを

float naifMatrix[3][3] = { 
    {2, 1, 3}, 
    {0, -1, 4}, 
    {1, 3, 0} 
}; 

問題であるように、配列の配列を使用することですコンパイル時には知られていない任意のサイズの行列を使用することができます)。ベクトルで作業して配列として表現するときは、この問題は見えません。私は

float vector[3] = {1, 2, 3}; 
norm(vector); 

をすれば、それは私がvectorが渡されると、それは(&vector[0]に変換され、あまり情報が失われ、基本的には、1つのトラックを保つために持っているnorm

よう
norm(float * vector); 

を宣言して、動作します長さの)。しかし、私はちょうど

gaussReduction(naifMatrix); 

を呼び出し、naifMatrixはないポインタへのポインタで、floatの配列へのポインタに変換(と当然のように)され

gaussReduction(float ** naifMatrix); 

ためにgaussReductionを宣言することはできません。このアレイの大きさはわからないので、gaussReductionを宣言する方法はありません。

もちろん、私は無効にポインターを渡すことで不正行為をすることができますが、逆参照する前に、正しいタイプ(float[3] *)にキャストする必要があります。これは先験的にわかりません。さらに、私は、void *を悪用することによって、厳密な型チェックである他の言語よりもCを使用する目的の1つを打ち負かすように思えます。

私が今までに見つけた最良の解決策は、構造体を使用することです。行列は、基本的にそのエントリと2つの次元のリストによって与えられます。だから私は

struct matrix { 
    float * begin; 
    int rows, columns; 
}; 

を行うと、

struct matrix matrix = {&naifMatrix[0], 3, 3}; 

問題としてそれを使用することができ、これはまだ迷惑であるということです。まず、double配列からstruct matrixを取得するのは大変です.2番目の配列では、次元を明示的に指定する必要があります。

struct matrix matrix = Matrix(naifMatrix); 

のような種類の「コンストラクタ」関数でこれをラップするとうれしいですが、私はこれを2つの理由で行うことはできません。まず、関数に引数としてnaifMatrixを渡す際に、上記と同じ問題があります。第二に、たとえそれを渡すことができたとしても、私はポインタを取得するので、次元に関する情報を得ることができませんでした(この場合、両方とも3です)。

マトリックスのデータムを渡して操作する方が賢明な方法はありますか?

+0

C *で*数値レシピのコピーを購入し、それを読むことをお勧めします。あなたはそこに必要なものすべてを学ぶでしょう。 –

+0

http://stackoverflow.com/questions/4051/passing-multidimensional-arrays-as-function-arguments-in-c related。 – Rozuur

+0

@David:ありがとうございますが、これは私がしたいことだけではありません。私はちょうどCを学ぶために遊んでいる、私は線形代数ライブラリを構築することを楽しみにしていない。 – Andrea

答えて

6

C99は、言語に可変長配列を追加しました:

_Bool gaussReduction(size_t rows, size_t cols, float matrix[rows][cols]); 

を使用すると、定義

float naifMatrix[3][3] = { 
    {2, 1, 3}, 
    {0, -1, 4}, 
    {1, 3, 0} 
}; 

を持っている場合は、

あなたが使用することができます
size_t rows = sizeof naifMatrix/sizeof *naifMatrix; 
size_t cols = sizeof *naifMatrix/sizeof **naifMatrix; 

経由次元で取得することができます繰り返しを最小限にするマクロ。

#define rowsof(MATRIX) (sizeof (MATRIX)/sizeof *(MATRIX)) 
#define colsof(MATRIX) (sizeof *(MATRIX)/sizeof **(MATRIX)) 
#define matrixarg(MATRIX) rowsof(MATRIX), colsof(MATRIX), (MATRIX) 

使用して、あなたは可変長配列を持って使用し

gaussReduction(matrixarg(((float [3][3]){ 
    {2, 1, 3}, 
    {0, -1, 4}, 
    {1, 3, 0} 
}))); 

で、代わりに変数のリテラル化合物を使用して、

gaussReduction(matrixarg(naifMatrix)); 

で終わるかと思います同等のC90コードと同じパフォーマンス特性 - 唯一得られるのは、より良い構文です:

// C99: 
_Bool gaussReduction(size_t rows, size_t cols, float matrix[rows][cols]) 
{ 
    // size_t i = ..., j = ... 
    float x = matrix[i][j]; 

/* C90: */ 
int gaussReduction(size_t rows, size_t cols, float *matrix) 
{ 
    /* size_t i = ..., j = ... */ 
    float x = matrix[i * cols + j]; 
+0

ありがとうございます!私はこれが彼が標準の以前のバージョンの本からCを勉強することによって得られるものだと思います... :-Dところで、固定サイズに関して可変サイズの配列を使用するとパフォーマンスが低下しますか? – Andrea

+0

@Andrea:可変長配列は、コンパイル時に配列のサイズが分からない限り、パフォーマンス上のペナルティしか持ちませんが、配列を関数の引数として渡すとこの情報は失われます。私の答えに相当するC90に関するいくつかの詳細を追加します... – Christoph

-1

あなたは、このように定義した場合:

float naifMatrix[][] = { 
    {2, 1, 3}, 
    {0, -1, 4}, 
    {1, 3, 0} 
}; 

をあなたはポインタの配列へのポインタを持っている必要があります。次に使用することができます

gaussReduction(float ** naifMatrix); 

私のCは錆びています。

+0

C配列はギザギザではありません - 2次元配列をpoiter-to-pointerに変換することはできません – Christoph

+0

'naifMatrix [] [] 'そのような配列。最初の配列添字のみがオプションです。これは 'naifMatrix [] [3]'だったはずです。 – Mahesh

+0

これはまさに私の問題です。多くの場合、2次元配列は配列へのポインタで変換されます。 – Andrea

関連する問題