4

次のステートメントを検討してください。

int    *pFarr, *pVarr;

int    farr[3] = {11,22,33};
int    varr[3] = {7,8,9};

pFarr = &(farr[0]);
pVarr = varr;

この段階では、両方のポインターがそれぞれの配列アドレスの先頭を指しています。*pFarr については現在 11 を、*pVarr については 7 を調べています。

同様に、*farr と *varr を介して各配列の内容を要求すると、11 と 7 も取得されます。

ここまでは順調ですね。

pFarr++では、 と を試してみましょうpVarr++。偉大な。予想どおり、現在 22 と 8 を見ています。

でも今...

上に移動しようとするfarr++varr++...「インクリメントする引数の型が間違っています」という結果になります。

これで、配列ポインターと通常のポインターの違いはわかりましたが、動作は似ているのに、なぜこの制限があるのでしょうか?

上記のコードで起こったこととは対照的ですが、同じプログラムで次の関数を表面上は正しい方法と別の間違った方法で呼び出すことができると考えると、これはさらに混乱します。 !?

working_on_pointers ( pFarr, farr );  // calling with expected parameters
working_on_pointers ( farr, pFarr );  // calling with inverted parameters 

.

void working_on_pointers ( int *pExpect, int aExpect[] ) {

    printf("%i", *pExpect);  // displays the contents of pExpect ok
    printf("%i", *aExpect);  // displays the contents of aExpect ok

    pExpect++;               // no warnings or errors
    aExpect++;               // no warnings or errors

    printf("%i", *pExpect);  // displays the next element or an overflow element (with no errors)
    printf("%i", *aExpect);  // displays the next element or an overflow element (with no errors)

}

配列ポインターとポインターが一部のコンテキストでは同様に動作するが、他のコンテキストでは異なる理由を誰かが理解するのを手伝ってくれますか?

どうもありがとう。

編集:私のような初心者は、このリソースからさらに利益を得ることができます: http://www.panix.com/~elflord/cpp/gotchas/index.shtml

4

6 に答える 6

8

違いはfarr++、効果を得るには、コンパイラがfarr配列の2番目の要素のアドレスに評価されるものを格納する必要があるためです。しかし、その情報のための場所はありません。コンパイラは3整数の場所のみを割り当てます。

これで、関数パラメーターが配列であると宣言すると、関数パラメーターは配列になりません。関数パラメーターはポインターになります。Cには配列パラメーターはありません。したがって、次の2つの宣言は同等です。

void f(int *a);
void f(int a[]);

角かっこで囲まれた数字は関係ありません。パラメータは実際にはポインタになるため、「サイズ」は無視されます。

これは関数の場合も同じです。次の2つは同等であり、パラメーターとして関数ポインターがあります。

void f(void (*p)());
void f(void p()); 

関数ポインタと関数の両方を呼び出すことはできますが(同じように使用されます)、関数はポインタではないため、関数に書き込むこともできません。単にポインタに変換されるだけです。

f = NULL; // error!

配列を変更できないのとほぼ同じ方法です。

于 2010-03-05T00:57:42.690 に答える
5

Cでは、配列に割り当てることはできません。だから、与えられた:

T data[N];

ここTで、はタイプでありN、は数値です。次のように言うことはできません。

data = ...;

上記を前提として、data++;に割り当てようとするとdata、エラーが発生します。

Cには、配列とポインターに関する1つの簡単なルールがあります。値のコンテキストでは、配列の名前は最初の要素へのポインターと同等であり、オブジェクトのコンテキストでは、配列の名前は配列と同等です。

オブジェクトコンテキストは、を使用して配列のサイズを取得するsizeofとき、またはそのアドレス(&data)を取得するとき、または配列の初期化時にです。他のすべてのコンテキストでは、値のコンテキストにあります。これには、配列を関数に渡すことも含まれます。

だから、あなたの関数:

void working_on_pointers ( int *pExpect, int aExpect[] ) {

と同等です

void working_on_pointers ( int *pExpect, int *aExpect ) {

表示されるのはポインターだけなので、関数は配列とポインターのどちらが渡されたかを判断できません。

次の質問への回答に詳細があります。

また、 C for smartiesのWebサイトのこの部分も参照してください。これは、非常によく書かれています。

于 2010-03-05T01:44:10.277 に答える
1

farrどちらもポインターではないため、インクリメントまたはvarr失敗を試みています。それぞれが配列です。配列の名前は、それ自体で評価されると (sizeof または address-of 演算子のオペランドとしては除く)、ポインターに割り当てられる正しい型の値(右辺値) に評価されます。それをインクリメントしようとするのは、 をインクリメントしようとするのと少し似ています17値 17 を含むint をインクリメントすることはできますが、17 をインクリメントすること自体は機能しません。配列の名前はそのようなものです。

2 番目の部分については、非常に単純です。配列型の関数パラメーターを宣言しようとすると、コンパイラーは黙ってそれをポインター型に「調整」します。そのため、あなたworking_on_pointersaExpectpExpectまったく同じタイプです。配列スタイルの表記にもかかわらず、aExpectタイプ「int へのポインター」を持つと定義しました。この 2 つは同じなので、同じように動作することが完全に予想されます。

于 2010-03-05T01:08:51.427 に答える
0

ここSOのポインタと配列の違いに関連して私が投稿したこの回答を見てください。

お役に立てれば。

于 2010-03-05T01:03:05.717 に答える
-1

わかりました、私は間違っているかもしれません。ただし、配列とポインタは交互に使用できます。

int * ptr = (int *)malloc(2* sizeof(int));
ptr[0]=1;
ptr[1]=2;

printf ("%d\n", ptr[0]);
printf ("%d\n", ptr[1]);

ここでポインタを宣言しましたが、今はそれを配列として扱っています。

さらに:

この定義の結果として、配列とポインターに適用される "配列添え字" 演算子 [] の動作に明らかな違いはありません。a[i] の形式の式では、配列参照 "a" は上記の規則に従ってポインターに崩壊し、式 p[i] のポインター変数と同じように添字が付けられます (ただし、最終的なメモリは質問 2.2 で説明されているように、アクセスは異なります)。いずれの場合も、式 x[i] (x は配列またはポインター) は、定義上、*((x)+(i)) と同じです。

参照: http://www.lysator.liu.se/c/c-faq/c-2.html

于 2010-03-05T02:24:41.343 に答える
-2

配列の基本概念を理解する必要があります。

配列を宣言するとき、つまり

int farr[]

あなたは実際にこの宣言でポインタを宣言しています

const int * farr

すなわち; 整数への「定数」ポインタ。したがって、 farr++ を実行すると、実際には定数であるポインターに加算しようとしているため、コンパイラーはエラーを出します。

理解する必要がある場合は、上記の宣言でポインターを宣言してみてください。通常のポインターでは有効な算術演算を行うことができません。

PS:Cでコーディングしている間は静かだったので、正確な構文についてはわかりません。しかし、肝心なのは、ポインターと定数ポインターの違いです。

于 2010-03-05T01:22:28.337 に答える