2010-12-17 7 views
13

二次元配列を表すのに二重ポインタを使用できないのはなぜですか?二次元配列を表すのに二重ポインタを使用できないのはなぜですか?

arr[2][5] = {"hello","hai"}; 
**ptr = arr; 

ここで、ダブルポインタ(** ptr)はこのサンプルでは機能しません。

+0

あなたの質問に似ているコードはありますか? –

+1

多次元配列から逃げる(おそらく小さな配列を除く)。 –

+2

@Alexandre C.多次元配列はシンプルで、便利で効率的です。なぜ彼らから逃げたいのですか? – Shahbaz

答えて

8

ポインタへのポインタは、各行(またはそのように思うのが望ましいと思われる場合は列)が他の行/列と異なる長さを持つことができることを意味します。二次元アレイは、Cで

void matrix_set(double *first, size_t row_size, size_t x, size_t y, double value) 
{ 
    first[y * row_size + x] = value; 
} 
+1

私の質問はなぜ、どのように働いているのかです。あなたは、コンパイラはあなたのためのオフセットの計算を行うようにする可変長配列を使用することができます – Thangaraj

7

また、ちょうど開始要素へのポインタ、および行/列当たりの要素数を指定する整数の2Dアレイを表すことができアレイのアレイ。それが最初に参照する必要があり、「2次元データ」を参照して

char array[2][6] = {"hello", "hai"}; 
char (*p)[6] = array; 
//char **x = array; // doesn't compile. 

ダブルポインタの場合:

あなたはへのポインタの配列は、それを参照するには、ないダブルポインタを必要としますポインタのの要素。しかし、C(配列の配列)の2次元配列はポインタの配列と同じではなく、2次元配列を定義するだけで対応するポインタの配列は存在しません。

2つの間の唯一の類似点は、データにアクセスするために使用される[][]構文です。データ自体はかなり異なった構造になっています。

1

まず法的なコードについて説明しましょう。いくつかの理由で、あなたが書いたもの(各宣言の前にcharがあると仮定して)はコンパイルされません:arr [0]には6個のcharがあり、そのサイズは5です。 ** pには、char arr [2] [5]と互換性のある型はありません。これらの問題を修正すると、次のようになります。

char arr[2][6] = { "hello", "hai" }; 
char (*p)[6] = arr; 

ダブルポインタなし。あなたは上記の中で、単一の文字にアクセスする場合、あなたは彼らが来たから要素を指定する必要があります。

char* pc = *arr; 

を使用すると、ARRの最初の要素から文字にアクセスしたい場合は、動作します。

C++には2次元配列がありません。上記の最初の定義はcharの配列[2]または配列[6]を定義します。 implicite配列からポインタへの変換の結果、charの配列[6]へのポインタが返されます。その後も、配列を持たないため、ポインタ変換の配列はありません。

3

可変サイズの多次元配列のように見えるオブジェクトを得るために各行へのポインタの配列を作ることは、であり、構文的な砂糖のために高価なデザインの選択です。それをしないでください。

可変サイズの多次元配列を行うための正しい方法のようなものです:

if (w > SIZE_MAX/sizeof *m/h) goto error; 
m = malloc(w * h * sizeof *m); 
if (!m) goto error; 
... 
m[y*w+x] = foo; 

あなたはそれが「きれいに見える」にしたい場合は、m[y][x]を書くことができますので、あなたはおそらく、別の言語を使用する必要がありますC++。

+3

: 'int型(* FOO)[COLS = malloc関数(はsizeof * FOO *行)'おなじみの 'FOOを使用することが可能になる[I] [j] '構文; – Christoph

+0

@Christoph:確かに、もしC99コンパイラがあれば、これは動作します。配列を渡した関数呼び出しに次元を適切に渡すように調整する必要があります。 –

33

私は

int array[10][6]; 

int **array2 = new int *[10]; 
for (int i = 0; i < 10; ++i) 
    array2[i] = new int[6] 

がメモリ内のように見えるし、それらがどのように異なる(そして、彼らはお互いにキャストすることができないことをどのように描くしようとするつもりです)

arrayは、次のようになります。

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
| | | | | | | | | | | | | ..............| | | (10*6 elements of type int) 
- - - - - - - - - - - - - - - - - - - - - - 
< first row >< second row> ... 

array2次のようになります。あなたがarray[x][y]を言うとき、それは*(((int *)array)+x*6+y)

ながら、あなたはarray2[x][y]を言うとき、それはそれ*(*(array2+x)+y)

に変換、静的な2次元配列をしているに変換

_ _ _ _ _ _ _ _ _ _ 
| | | | | | | | | | | (10 elements of type int *) 
- - - - - - - - - - 
| |  ....  |  _ _ _ _ _ _ 
| |    \-->| | | | | | | (6 elements of type int) 
| |      - - - - - - 
| | 
| |  _ _ _ _ _ _ 
| \ -->| | | | | | | (6 elements of type int) 
|  - - - - - - 
| 
| 
|  _ _ _ _ _ _ 
    \ -->| | | | | | | (6 elements of type int) 
     - - - - - - 

実際には1行に1行の配列を持つ1次元配列です。インデックスは、式row * number_of_columns_in_one_row + columnによって計算されます。

動的2Dアレイは、しかし、ポインタのわずか1Dアレイです。次に、各ポインタは、別の1d配列を指すように動的に割り当てられます。実際、そのポインタは何でもかまいません。 NULLであるか、単一の変数を指すか、別の配列を指すことができます。これらのポインタはそれぞれ個別に設定されるため、異なる性質を持つことができます。あなたはどこかarrayのポインタを渡す必要がある場合

、あなたは何が起こるか想像(int **にキャストすることはできませんarrayの細胞のint値はポインタとして解釈され、逆参照されている - 。>バムセグメンテーションフォールト!の! )。しかし、arrayint [6]の1d配列として考えることができます。つまり、要素の1次元配列で、タイプはint [6]です。これを書き留めるには、

int (*p)[6] = array; 
関連する問題