0

これが事です。ポインタから配列へのポインタなどで作成される多次元配列(しばらく2Dを考えてみましょう)の概念を完全に理解できます...

次のようにします。

// we can use dynamically defined size n and m
int n = 3, m = 5 ;
int **T = new int *[n];
for (int i = 0 ; i < n ; ++i)
    T[i] = new int[m];

私たちが得たものは:(私がここにいるかどうかを確認してください)

  • メモリ内のどこかに配置された、5 int の 3 ブロックのメモリ
  • ints のブロック数 (行数) と同じサイズのメモリの 1 つの追加ブロック。このブロックは、これらの int 行へのポインターの配列です (通常、int のようなポインターの場合は 4 バイト)。
  • 私たちが最も関心を持っているのは、(**T) 型の T であり、ポインターへのポインターです。これはまさにポインターの配列へのポインターです。C++ では、配列は実際にはメモリのブロックを指すポインターであるため、t[] または t[0] は *t を意味し、t[x] は *(t+バツ)。

問題は、次のように sth を実行する場合です。

int n = 3, m = 5 ;
int T[n][m] ;

私たちが持っているのは、私が前に示したことを行うことができたものではありません. 奇妙になります。Tとは何ですか?T を printfing すると、T[0] と同じ値が得られます。行へのポインターの配列を追加せずに、サイズが n*m の int のブロックを予約したようです。

私の質問は次のとおりです。コンパイラは配列の次元と行と列の数を覚えていますか? T[i][j] を要求すると、実際には *(T+i*n+j) が要求されるため、この n はどこかに保存されますか? 問題は、このこと (T) を関数に渡そうとするときです。理由はわかりませんが、n と m が定数の場合、T をこの配列へのポインターとして渡して、このプログラムのように機能させることができます。

#include <stdio.h>
const int n = 3, m = 4 ; // this is constant!
void add_5(int K[][m])
{
    for (int i = 0 ; i < n ; ++i)
        for (int j = 0 ; j < m ; j++)
            K[i][j] += 5 ;
}
int main()
{
    // n x m array the most straight forward method
    int T[n][m] ;
    for (int i = 0 ; i < n ; ++i)
        for (int j = 0 ; j < m ; ++j)
            T[i][j] = i*m + j ;

    for (int i = 0 ; i < n ; ++i)
    {
        for (int j = 0 ; j < m ; j++)
            printf("%d ",T[i][j]) ;
        printf("\n") ;
    }
    printf("\n") ;

    // adding 5 to all cells
    add_5(T) ;
    printf("it worked!!\n") ;

    for (int i = 0 ; i < n ; ++i)
    {
        for (int j = 0 ; j < m ; j++)
            printf("%d ",T[i][j]) ;
        printf("\n") ;
    }

    int ss ;
    scanf("%d",&ss) ;
}

しかし、n と m が一定でない場合はできません。したがって、動的に作成された多次元配列のポインターを、手動でメモリを割り当てずに関数に渡す必要があります。これを行う方法?

4

2 に答える 2

5

C++ では、配列は実際にはメモリ ブロックを指すポインタです。

絶対違う。配列はポインターとは完全に別物です。この混乱が生じる理由は、配列からポインターへの変換と呼ばれる標準的な変換のためです。検討:

int arr[10];

変数arrは配列を表します。それはまったくポインターではありません。多くの場合、配列の名前が最初の要素へのポインタに変換されることがあります。つまり、変換により に変換されますint*

int T[n][m] ;

この場合、T「s の配列のn配列m int」です。T両方を印刷T[0]すると同じ結果が得られると述べましたが、これは配列からポインターへの変換によるものです。

  1. Tは、最初の要素へのポインターに変換できます。つまり、int (*)[m]の最初の要素T自体がm要素を持つ配列であるためです。

  2. T[0]は、最初のサブ配列の最初の要素へのポインターに変換できます。T[0][0]したがって、 typeの要素へのポインターを取得しますint*

これらのポインターは、配列がメモリ内に配置される方法により、同じアドレスを保持します。配列が始まるアドレスは、その配列の最初の要素と同じアドレスです。ただし、ポインターは同じように動作しません。から得られたポインターをインクリメントするTと、次の部分配列に移動します。からのポインタをインクリメントするT[0]と、次の に移動しますint

動的に割り当てられた「2D 配列」と比較して、2D 配列がメモリ内でどのようにレイアウトされるかを示す図を見ると役立つ場合があります。3 行 3 列の 2D 配列は次のようになります。

  0,0   0,1   0,2   1,0   1,1   1,2   2,0   2,1   2,2
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ int │ int │ int │ int │ int │ int │ int │ int │ int │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘

一方、3 行 3 列の「2D 配列」を動的に割り当てた場合:

┌─────┐
│     │ // The int**
└──╂──┘
   ┃
   ▼
┌─────┬─────┬─────┐
│     │     │     ┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓  // An array of int*
└──╂──┴──╂──┴─────┘                            ┃
   ┃     ┗━━━━━━━━━━━━━━━┓                     ┃
   ▼                     ▼                     ▼
┌─────┬─────┬─────┐   ┌─────┬─────┬─────┐   ┌─────┬─────┬─────┐
│ int │ int │ int │   │ int │ int │ int │   │ int │ int │ int │ // Arrays of ints
└─────┴─────┴─────┘   └─────┴─────┴─────┘   └─────┴─────┴─────┘
  0,0   0,1   0,2       1,0   1,1   1,2       2,0   2,1   2,2

コンパイラは配列の次元と行と列の数を覚えていますか?

はい、配列型の変数がある場合、配列のサイズはその型の一部です。コンパイラは変数の型を常に認識しています。

T[i][j] を要求すると、実際には *(T+i*n+j) が要求されるため、この n はどこかに保存されますか?

T[i][j]は と同等*(*(T + i) + j)です。これが何をするのかを理解しましょう。まず、配列からポインタへの変換が によって行われT、 が与えられますint (*)[m]。次にこれに追加して、 th サブ配列iを指すように移動します。iこれは、部分配列を取得するために逆参照されます。次に、このサブ配列も配列からポインターへの変換を受け、int*. 次に、これに追加して、そのサブ配列内のthオブジェクトjへのポインターを取得します。これは、それを与えるために逆参照されます。jintint

問題は、このこと (T) を関数に渡そうとするときです。理由はわかりませんが、n と m が定数の場合、T をこの配列へのポインターとして関数に渡すことができます。

実は嘘です。2D 配列を関数に渡していません。実際、配列型の引数などというものはありません。あなたの引数int K[][m]は実際には と同等int (*K)[m]です。つまり、配列型の引数はすべてポインターに変換されます。

したがって、この関数をadd_5(T)で呼び出すと、 で示される配列が渡されませんTTは実際に配列からポインターへの変換を受けておりint (*)[m]このポインターは関数に渡されています。

于 2013-05-05T23:04:12.707 に答える