1

だから私は2つのことを理解しようとしています:

  1. これらの 3 つの表現の違いは何ですか?
  2. 最初の式 (A) に相当するものは何ですか?

コードは次のとおりです(固定):

#include "stdafx.h"

void someFunc(double** pArray, int length)
{
    for(int i = 0; i < length; i++)
    {
        //this works perfectly
        double expressionA = *(*pArray + i);
        //this crashes : Unhandled exception at 0x00da13ff in pptrtest.exe: 0xC0000005: Access violation reading location 0xcccccccc.
        double expressionB = **(pArray + i);
        //this crashes : Unhandled exception at 0x00da13ff in pptrtest.exe: 0xC0000005: Access violation reading location 0xcccccccc.
        double expressionC = *pArray[i];
    }
}
int main()
{
    double arr[] = { 1, 2, 3, 4, 5 };

    double* pArr = arr;

    someFunc(&pArr, sizeof arr / sizeof arr[0]);

    return 0;
}
4

5 に答える 5

3

問題は、[] が * の前に適用されるため、 expr C で実行していることだと思います

*(ppDoubleArray[i])

実際にはexpr Bと同等ですが、expr Aはそうです

(*ppDoubleArray)[i]

(式の 1 が i であると仮定すると、それ以外の場合はとにかく異なります)。

于 2011-05-12T23:16:50.043 に答える
1

double のポインターへのポインターがあります。double の配列へのポインターと考えてください。いずれにせよ、以下はその意味です。

  1. double expressionA = *(*ppDoubleArray + 1);以下と同じです:double expressionA = *((*ppDoubleArray) + 1);
  2. double expressionB = **(ppDoubleArray + 1);と同じです: これは、存在しないと推測しているものをdouble expressionB = *(*(ppDoubleArray + 1));逆参照することを意味します。ppDoubleArray[1]
  3. double expressionC = *ppDoubleArray[i];-- 繰り返しますが、存在しないものをdouble expressionC = *(ppDoubleArray[i]);逆参照しています。ppDoubleArray[i]

他の皆さんもおっしゃっているように、優先順位に注意する必要があります。基本的に、最初に逆参照してから、配列にインデックスを付けます。

于 2011-05-12T23:23:20.290 に答える
1
double expressionB = **(ppDoubleArray + 1);

この男のメモリを見てみましょう。スタックには、double へのポインタへのポインタがあります。したがって、32 ビット プロセッサのメモリ内のアドレスの場合、スタックは次のようになります。

スタック: |ppDoubleArray ptr |ローカル変数、その他の引数、またはガベージ |その他のローカル/etc
addr: スタックから |0 バイト |スタックから 4 バイト |8 バイト...

したがって、式の最初の部分を見ると、

  (ppDoubleArray + 1)

これは、「ポインタを 1 つ過ぎて移動する」ことを意味しますppDoubleArray。メモリ内の次のスポットに移動して、次のポインターに移動します。過去の思い出の次のスポットはppDoubleArray?上記のスタックを見てください。おそらくいくつかのローカル変数または他の引数です。これで、誰が何を知っているか (多分、length の内容? double の 1 つ? ゴミ?) がわかり、それをどこかの有効なアドレスであるかのように扱うことになります。次に、逆参照することにより、想定されるポインターをたどります。

   **(ppDoubleArray + 1)

そしてクラッシュ!

たとえば、長さが 5 の場合、ppDoubleArray+1 は 5 を取得し、"5" を逆参照して、そのアドレスで何かを探します。

このコード:

   double expressionC = *ppDoubleArray[i];

逆参照よりも[] 優先されます。したがって、過去の i 番目のメモリ位置に移動し、ppDoubleArrayそれが配列を指していると想定します。

ただし、親を使用して操作の順序を並べ替えるとうまくいきます。

   (*ppDoubleArray)[i]
于 2011-05-12T23:24:57.980 に答える
0

アスキーアート時間:
--->=参照解除

double expressionA = *(*ppDoubleArray + 1);

ppDoubleArray  ---> .  
                    +1  
                    . ---> expressionA

double expressionB = **(ppDoubleArray + 1);

ppDoubleArray
     +1
      . ---> . ---> expressionB

double expressionC = *ppDoubleArray[i];

ppDoubleArray
     +i
      . ---> . ---> expressionC
于 2011-05-12T23:30:50.207 に答える
0

ppDoubleArray が double の配列へのポインタであると仮定します。

2 つ目は、配列から正しいインデックスを選択せず​​に配列へのポインタに 1 を追加しているため、クラッシュします。

3 つ目は、演算子の優先度が原因でクラッシュします。配列ではない th 要素を選択しi(i が 0 でない限り)、それを逆参照しています。

ここで覚えておくべき重要なことは、配列へのポインター (またはポインターへのポインター) を処理する方法です。一度逆参照して配列を取得し、その時点で算術演算を実行してから、再度逆参照して取得します。要素。

于 2011-05-12T23:17:27.540 に答える