2011-11-21 23 views
6

私は、静的に割り当てられた多次元配列を一時変数に割り当てたいと考えています。次の例を考えてみましょう:多次元配列を一時変数に割り当てる方法は?

void foo(int b[3][2]) 
{ 
    b[1][1] = 1; // no segmentation fault 
} 

int main() 
{ 
    int a[3][2] = {{1, 2}, {11, 12}, {21, 22}}; 

    foo(a); 

    int** c; 
    c = (int**)&a; 
    c[1][1] = 1; // segmentation fault on execution 

    int* d[3]; 
    d[0] = (int*)&(a[0]); 
    d[1] = (int*)&(a[1]); 
    d[2] = (int*)&(a[2]); 
    d[1][1] = 1; // no segmentation fault 

    return 0; 
} 

基本的に私は、コンパイラは、パラメータfoo()bで何をやりたいです。しかし、唯一の解決策は、dです。それほど複雑な方法はありませんか?

+0

2次元配列がどういうわけかポインタへのポインタに直接キャストされていると思うのは奇妙です。 – tenfour

答えて

11

cdeclman page)はあなたの友達です:

cdecl> explain int b[3][2] 
declare b as array 3 of array 2 of int 
cdecl> declare b as pointer to array 2 of int 
int (*b)[2] 

ので、これを試してみてください。

void foo(int b[3][2]) 
{ 
    b[1][1] = 1; // no segmentation fault 
} 

int main() 
{ 
    int a[3][2] = {{1, 2}, {11, 12}, {21, 22}}; 

    foo(a); 

    int (*b)[2] = a; 

    b[1][1] = 1; 

    return 0; 
} 
+0

huh - これは新しいものです。 cdeclはどこですか? – sehe

+0

OMG _cdecl_:D:D:Dこれは見たことがない:Dオンライン版:@sehe - http://cdecl.org/ –

+1

+1、cdeclのおかげで;-) –

9

int[3][2]int**は互換性のないタイプです。あなたは人を別の人にキャストすることはできません。

int (*c)[2]; 
c = a; //no need to cast 
c[1][1] = 1; //ok 

それとも、(初期化だけでなく、宣言)これを行うことができます:

これを試してみてくださいルールの

int (*c)[2] = a; //no need to cast 
c[1][1] = 1; //ok 

親指:

  • CスタイルのキャストをC++で使用しないでください。 C++スタイルのキャストを使用します。

    prog.cpp:5: error: invalid static_cast from type ‘int (*)[3][2]’ to type ‘int**’ 
    

    をしかし、Cスタイルのキャストは、(罰金、それをコンパイルします - あなたがC++を使用していたスタイルのキャストが、コンパイラはずっと前にあなたに(問題を参照するには、コードを実行する必要が)(ideone)の問題を話したんだろうideone)をご覧ください。

  • キャストを使用するときはいつでも、C++スタイルのキャストも、プログラムが期待どおりに動作しない場合、最初の疑問はキャスト自体でなければなりません。

+1

あなたはタイプミスがあります。 –

+1

@KirilKirov:修正されました。ありがとう。 – Nawaz

2

あなたがC++ 11標準の十分な部分をサポートし、かなり近代的なコンパイラを使用している場合は、autoを使用することができます。

もちろん
int a[3][2] = ...; 
auto &b = a; 
b[1][1] = 1; // a[1][1] will be set 

abの両方を定義する必要がありますそれが働くのと同じ範囲で。あなたが例えば機能でautoパラメータを持つことはできません(つまり、テンプレートがのためにあるものだ。)

5

あなたは他の回答から、aの種類がint**と実際に同等ではありません、今はおそらく気づいているとして - それをjsut はそれに(値によって返された/渡された)ときにを崩壊させます。

typedef std::array<std::array<int, 2>, 3> M23; 

void foo(M23& b) 
{ 
    b[1][1] = 1; 
} 

int main() 
{ 
    M23 a = {{1, 2}, {11, 12}, {21, 22}}; 

    foo(a); 

    M23 d = a; 
    d[1][1] = 1; 
} 
+1

+1誰もが 'std :: array'を好きです:-) –

+1

@sehe:これはいいですが、質問に答えてOPのコードの問題を説明する必要があります。一度それを説明したら、より良い代替ソリューションを提案することができます。 – Nawaz

1

(コンパイルするgcc -Wall -g bidim.c -o bidimを使用して)明示的にキャストし、その次に

c = &a; 

GCCコンパイラを書くしようとしないでください、あなた与え :より多くのC++方法はあり

int (*b)[2] = a; // would solve that 

正しい警告:

bidim.c:13:7: warning: assignment from incompatible pointer type [enabled by default] 

そして、2D行列は、1D配列へのポインタの配列として実装されていないことに気づくべきです。

0

別の可能性はstructでそれをカプセル化することであるポインタ

int (*f)[2] = a; 
f[1][1] = 1; 

typedef int thing_t[3][2]; 
thing_t& e = a; 
e[1][1] = 1; 

のようにtypedefで参照を使用している私の心に来る最初の事。