39

良い(そして機能する)解決策を提供することについていくつかの質問があることは知っていますが、これを達成するための最良の方法を明確に述べている私見はありません。したがって、いくつかの 2D 配列があるとします。

int tab1[100][280];

この 2D 配列を指すポインターを作成します。これを達成するために、次のことができます。

int (*pointer)[280]; // pointer creation
pointer = tab1; //assignation
pointer[5][12] = 517; // use
int myint = pointer[5][12]; // use

または、代わりに:

int (*pointer)[100][280]; // pointer creation
pointer = &tab1; //assignation
(*pointer)[5][12] = 517; // use
int myint = (*pointer)[5][12]; // use 

OK、どちらもうまくいくようです。今私は知りたいです:

  • 1番目と2番目、どちらがいいですか?
  • コンパイラにとってどちらも等しいですか?(スピード、パフォーマンス...)
  • これらのソリューションの1つは、他のソリューションよりも多くのメモリを消費していますか?
  • 開発者がより頻繁に使用するものは何ですか?
4

4 に答える 4

36
//defines an array of 280 pointers (1120 or 2240 bytes)
int  *pointer1 [280];

//defines a pointer (4 or 8 bytes depending on 32/64 bits platform)
int (*pointer2)[280];      //pointer to an array of 280 integers
int (*pointer3)[100][280]; //pointer to an 2D array of 100*280 integers

WhozCraigによって指摘された操作を除いて、同じバイナリを使用pointer2または生成します。pointer3++pointer2

使用をお勧めしtypedefます(上記と同じバイナリコードを生成しますpointer3

typedef int myType[100][280];
myType *pointer3;

注: C++11 以降、キーワードusingの代わりにキーワードを使用することもできます。typedef

using myType = int[100][280];
myType *pointer3;

あなたの例では:

myType *pointer;                // pointer creation
pointer = &tab1;                // assignation
(*pointer)[5][12] = 517;        // set (write)
int myint = (*pointer)[5][12];  // get (read)

注:配列tab1が関数本体内で使用されている場合 => この配列はコール スタック メモリ内に配置されます。ただし、スタック サイズには制限があります。空きメモリ スタックより大きい配列を使用すると、スタック オーバーフロークラッシュが発生します。

完全なスニペットは、gcc.godbolt.orgでオンラインでコンパイルできます。

int main()
{
    //defines an array of 280 pointers (1120 or 2240 bytes)
    int  *pointer1 [280];
    static_assert( sizeof(pointer1) == 2240, "" );

    //defines a pointer (4 or 8 bytes depending on 32/64 bits platform)
    int (*pointer2)[280];      //pointer to an array of 280 integers
    int (*pointer3)[100][280]; //pointer to an 2D array of 100*280 integers  
    static_assert( sizeof(pointer2) == 8, "" );
    static_assert( sizeof(pointer3) == 8, "" );

    // Use 'typedef' (or 'using' if you use a modern C++ compiler)
    typedef int myType[100][280];
    //using myType = int[100][280];

    int tab1[100][280];

    myType *pointer;                // pointer creation
    pointer = &tab1;                // assignation
    (*pointer)[5][12] = 517;        // set (write)
    int myint = (*pointer)[5][12];  // get (read)

    return myint;
}
于 2013-02-11T09:17:23.090 に答える
11

どちらの例も同等です。ただし、最初のものはそれほど明白ではなく、より「ハック」ですが、2番目のものは意図を明確に示しています。

int (*pointer)[280];
pointer = tab1;

pointer280 個の整数の 1D 配列を指します。割り当てでは、実際には の最初のを割り当てますtab1。これは、配列をポインター (最初の要素) に暗黙的にキャストできるため機能します。

を使用している場合、C は配列の配列 ( is 型) としてpointer[5][12]扱うため、ここには (少なくとも意味的には) 別の暗黙のキャストがあります。pointerpointer[5]int[280]

2 番目の例では、2D 配列へのポインターを明示的に作成します。

int (*pointer)[100][280];
pointer = &tab1;

セマンティクスはここでより明確です:*pointerは 2D 配列であるため、 を使用してアクセスする必要があります(*pointer)[i][j]

どちらのソリューションも同じ量のメモリ (1 ポインター) を使用し、同じ速度で実行される可能性が高くなります。内部的には、両方のポインターが同じメモリ位置 (tab1配列の最初の要素) を指すことさえあり、コンパイラーが同じコードを生成する可能性さえあります。

何が起こっているのかを理解するには、C で配列とポインターがどのように機能するかを深く理解する必要があるため、最初の解決策は「より高度な」ものです。2番目のものはより明確です。

于 2013-02-11T10:00:37.993 に答える
10

int *pointer[280];//int 型の 280 個のポインターを作成します。

32 ビット OS では、ポインタごとに 4 バイト。したがって、4 * 280 = 1120 バイトです。

int (*pointer)[100][280];// [100][280] int の配列を指すために使用されるポインタを 1 つだけ作成します。

ここではわずか 4 バイトです。

int (*pointer)[280];あなたの質問に来て、int (*pointer)[100][280];[100] [280]の同じ2D配列を指していますが、異なります。

ifint (*pointer)[280];がインクリメントされると、次の 1D 配列を指しますが、asint (*pointer)[100][280];は 2D 配列全体を横切り、次のバイトを指します。そのメモリがプロセスに属していない場合、そのバイトにアクセスすると問題が発生する可能性があります。

于 2013-02-11T09:14:26.710 に答える