2012-04-20 12 views
17

次のコードは何をしていますか?配列へのポインタC++

int g[] = {9,8}; 
int (*j) = g; 

私が理解しているように、2つの整数の配列へのポインタを作成しています。 しかし、その後、なぜこの仕事ん:

int x = j[0]; 

、これは動作しません:

int x = (*j)[0]; 
+15

@mjfgates:配列はポインタではありません。人々にそれを知らせないでください。 –

+7

@mjfgates実際にCとC++には配列オブジェクトがあります。たとえば、配列から配列の最初の要素へのポインタへの非正規の変換を引き起こすような変わった規則が存在するだけです。 – bames53

答えて

37

あなたの例ではかっこは余分です。ポインタが関係する配列があるのか​​どうか気にしない - それだけでint型

int g[] = {9,8}; 
    int (*j) = g; 

へのポインティングも

のように書き換えることができ
int g[] = {9,8}; 
    int *j = g; 

のように書き換えることができることを知っています

int g[] = {9,8}; 
    int *j = &g[0]; 

アレイへのポインタは、

のようになります。 10
int g[] = {9,8}; 
    int (*j)[2] = &g; 

    //Dereference 'j' and access array element zero 
    int n = (*j)[0]; 

ここでは、このリンクで良いポインタ宣言の読み込み(とどのようにそれらを完全に理解する)あります:http://www.codeproject.com/Articles/7042/How-to-interpret-complex-C-C-declarations

+0

この記事は非常に参考になります。特に右から左へのルール、ありがとうございます。 –

+0

は、 'int(* j)[2] =&g;'で '2'が必要ですか? '2'が省略されても配列へのポインタではないでしょうか? – johnbakers

+0

@johnbakersはい配列の長さを指定することは絶対に必要です。そうしないと、配列へのポインタがなくなり、キャストを使用しない限りコードはコンパイルされません。配列へのポインティングは、コンパイル時にその長さを知っていることを意味します。 MSVC++で配列の長さを省略した結果のコンパイラメッセージは 'エラーC2440: '初期化中'を読み込みます: 'int(*)[2]'から 'int(*)[]'に変換できません。 –

9

j[0];intへのポインタを参照解除するので、そのタイプはintです。

(*j)[0]には型がありません。 *jintへのポインタを逆参照するので、intを返し、(*j)[0]intを参照解除しようとします。それはint x = 8; x[0];のようなものです。

+3

また、 'j [0]'は '*(j + 0)'と同等であることに注意してください。したがって、 '(* j)[0]'は '*(*(j + 0)+ 0)'に相当する 'j [0] [0]'に相当します。 '。あなたがそれを見ても、それはうまくいかない。 – chris

+0

それでは、どのように配列要素のグループへのポインタを作成しますか? –

+0

'j [1] == *(j + 1)==配列の次の要素'のように、ポインタを最初の要素に設定し、配列のように使用します。 – chris

19
int g[] = {9,8}; 

は、これは[2] int型のオブジェクトを宣言し、{9にその要素を初期化、8}

int (*j) = g; 

これは* int型のオブジェクトを宣言し、そしてGの最初の要素へのポインタとそれを初期化します。

2番目の宣言がj以外の何かでjを初期化するという事実はかなり奇妙です。 CとC++は配列に関するこれらの奇妙な規則を持っています。これもその1つです。ここで、表現gは、オブジェクトgを参照する左辺値から暗黙的にgの最初の要素を指すタイプint*の右辺値に変換されます。

この変換はいくつかの場所で行われます。実際にはg[0]を実行したときに発生します。配列インデックス演算子は実際には配列上では動作せず、ポインタに対してのみ動作します。そのため、というステートメントは、が初期化されたときと同じ暗黙の変換を行うため、g[0]が発生します。

配列へのポインタは、この

int (*k)[2]; 

のように宣言されます(右これは

int x = (*k)[0]; 

を使用されるかについて正確だと宣言するための構文、すなわちどのよう"declaration follows use"、注意してくださいタイプの変数は、の構文を模倣しています。のタイプの変数を使用します。

しかし、通常、配列へのポインタは使用しません。配列に関する特別な規則の全目的は、配列のように配列要素へのポインタを使用できるようにするためです。だから、慣用的なCは、一般的に配列とポインタが同じものではないことに気をつけません。


例:

void foo(int c[10]); // looks like we're taking an array by value. 
// Wrong, the parameter type is 'adjusted' to be int* 

int bar[3] = {1,2}; 
foo(bar); // compile error due to wrong types (int[3] vs. int[10])? 
// No, compiles fine but you'll probably get undefined behavior at runtime 

// if you want type checking, you can pass arrays by reference (or just use std::array): 
void foo2(int (&c)[10]); // paramater type isn't 'adjusted' 
foo2(bar); // compiler error, cannot convert int[3] to int (&)[10] 

int baz()[10]; // returning an array by value? 
// No, return types are prohibited from being an array. 

int g[2] = {1,2}; 
int h[2] = g; // initializing the array? No, initializing an array requires {} syntax 
h = g; // copying an array? No, assigning to arrays is prohibited 

配列は、CおよびCにおける他のタイプととても矛盾しているので++あなただけ避けなければならない:(int g[2] = {1,2}; int h[2]; h = g;たとえば次のような配列をコピーすることはできません)それら。 C++にはより一貫性のあるstd::arrayがあり、静的なサイズの配列が必要なときに使用してください。動的なサイズの配列が必要な場合、最初のオプションはstd :: vectorです。

+0

+1を渡した時間にもかかわらず答えます。 –