2016-07-05 13 views
-1
#include<bits/stdc++.h> 
using namespace std; 
int main() 
{ 
    int a[101][101]; 
    a[2][0]=10; 
    cout<<a+2<<endl; 
    cout<<*(a+2)<<endl; 
    cout<<*(*(a+2)); 
    return 0; 
} 

なぜa + 2と*(a + 2)の値が同じですか?前もって感謝します!2次元配列はどのようにメモリに格納されていますか?

+2

そのようなことを信じるならば、偶然かもしれません... –

+0

印刷されたポインタの値が同じであっても、タイプはありません。 – Jarod42

+1

あなたは運がいいです!今日、そして今日だけ、stackoverflow.comで私たちは特別なことをしています:あなた自身の質問に答えてください!小さな配列を作成して、 'int a [2] [2]'と言う。それに4つの値、例えば1、2、3、4を入れます。最初の要素 'int * p =&a [0] [0];'へのポインタを取得します。次に、デバッガで、 'p'が指しているものを見て、あなた自身の質問に答えます。どのようなバーゲン! –

答えて

4

aは、2次元配列です。つまり、配列の配列を意味します。しかし、は、適切な文脈で使用された場合、配列へのポインタにを崩壊させます。だから、:

  • a+2に、aは、あなたがのostreamに、あなたはこの配列の最初の要素のアドレスを取得されて渡すとサイズ101の配列をint型へのポインタに減衰することが&(a[2][0])
  • であります*(a+2)は、定義によってであるa[2]a[2][0]で始まるサイズ101の配列です。これは、intへのポインタに崩壊し、そしてあなたがその最初の要素のアドレスを取得するのostreamに渡したときに、それが定義a[2][0]でまだ&(a[2][0])
  • **(a+2)あるです。あなたはのostreamにそれを渡すときには、そのint型の値を取得し、ここ10

しかし、注意してください:a + 2a[2]は両方とも同じアドレスへのポインタ(static_cast<void *>(a+2)static_cast<void *>(a[2])と同じである)であるが、これらは異なるへのポインタでありますtypes:最初はint型の配列101を指し、後者はint型を指します。あなたは、配列の名前は、暗黙的にまれな例外を除いて、その最初の要素へのポインタに変換され、この

T a[N]; 

ような配列を持っている場合は

+0

ありがとう!それはかなり役に立ちました。 – Shubham

1

それはメモリ内にこのように保存されているように、2次元アレイは、アレイの配列である:*(v + y * M + x)(ここで、M:

char v[2][3] = {{1,3,5},{5,10,2}}; 

Content: | 1 | 3 | 5 | 5 | 10 | 2 
Address: v v+1 v+2 v+3 v+4 v+5 

Vにアクセスするには、[X] [Y]、コンパイラは、として書き換え第二次元はVにアクセスするために、例えば

)が指定されている[1] [1]、コンパイラは、=>*(v + 4)

これはない同じであることに注意してください*(v + 1*3 + 1)として書き換えますポインター(char **)へのポインターとして。 ポインタへのポインタは配列ではありません。ポインタには、別のアドレスを含むメモリセルが含まれています。ポインタへのポインタを使用して、2次元配列のメンバーにアクセスする

、これが行われているものである。

char **p; 
/* Initialize it */ 
char c = p[3][5]; 
  1. 移動pの内容によって指定されたアドレスに、
  2. そのアドレスにオフセットを追加します(このケースでは3)。
  3. そのアドレスに移動し、その内容(新しいアドレス)を取得します。
  4. 新しいアドレス(この場合は5)に2番目のオフセットを追加します。
  5. そのアドレスの内容を取得します。

    char p[10][10]; 
    char c = p[3][5]; 
    
    1. pのアドレスを取得し、最初のオフセット(3)を乗じを合計:

    一方、従来の2次元アレイを介してメンバーにアクセスするために、これらのステップであります行(10)の寸法。

  6. 結果に2番目のoffset(5)を追加します。
  7. そのアドレスの内容を取得します。
1

(例えばとしてsizeofオペレータに配列名を使用して)。

したがって、たとえば式(a + 2)aは、値&a[0]T *に変換されます。

あなたの例のwuth配列と比較

int a[101][101]; 
発現の

a + 2 
int (*)[101]

タイプ及びアレイの最初の「行」へのポイントの右辺値に変換されます。 a + 2は配列の3番目の「行」を指します。行のタイプはint[101]

です。式*(a+2)は、この第3行に配列int[101]の配列を与えます。そして、この配列は式の中で使われているように、int *の最初の要素へのポインタに変換されます。

3番目の行が占めるメモリ領域の開始アドレスと同じです。

(a + 2)はタイプint (*)[101]であり、式*(a + 2)はタイプint *です。しかし、両方とも同じ値を返します。つまり、アレイの3行目が占めるメモリ領域の開始アドレスaです。

+0

ありがとう!それはかなり役に立ちました。 – Shubham

0

配列の最初の要素は配列自体と同じ場所にあります - 配列には "空きスペース"がありません。

cout << a + 2

aは暗黙&a[0]、その最初の要素へのポインタに変換され、a + 2aの第三の要素、&a[2]の位置です。

cout << *(a + 2)では、の配列*(a + 2)は、最初の要素のポインタ&a[2][0]に変換されます。

aの3番目の要素の場所とaの3番目の要素の最初の要素の場所が同じなので、出力は同じです。

0

私はメモリがコンパイラによってマッピングされているどのように説明してみましょう:

はのは、より実用的な例の多次元配列について考えてみましょう:あなたはコマンドを実行することができます

int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; 

x/10w a 
GDBで

とメモリを見て:

0x7fffffffe750: 1 2 3 4 
0x7fffffffe760: 5 6 7 8 
0x7fffffffe770: 9 0 

各要素はタイプ(32ビット/ 4バイト)に格納されています。 Soは行列の最初の要素は、に格納されている:

1) a[0][0] -> 0x7fffffffe750 
2) a[0][1] -> 0x7fffffffe754 
3) a[0][2] -> 0x7fffffffe758 
4) a[1][0] -> 0x7fffffffe75c 
5) a[1][1] -> 0x7fffffffe760 
6) a[1][2] -> 0x7fffffffe764 
7) a[2][0] -> 0x7fffffffe768 
     ... 

コマンド:それが原因 ポインタaritmeticのアドレス0x7fffffffe768を印刷する

std::cout << a + 2 << '\n' 

の タイプint **なので、ポインタへのポインタです。 a + 2はa [0](第1行)+ 2である。結果は第3行へのポインタ である。

*(A + 2)が第三の行をdeferences、すなわち{7,8,9}

だ第3段目は、それがintへのポインタだ、intの配列です。

オペレータ< <は、そのポインタの値を出力します。

+0

この例では、実際に 'int [3] [3]'の型ではありませんか? – wally

+0

@flatmouseあなたが正しいです。コンパイル時に静的なサイズなので、型がint [3] [3]であると言う方がより正確です。 –

関連する問題