39

1 次元配列の場合 x=a[i]は と同等であることはわかってx=*(a+i)いますが、ポインターを使用して 2 次元配列の要素にアクセスするにはどうすればよいですか?

4

6 に答える 6

54

要約:として定義された多次元配列がある場合int [][]、 は次x = y[a][b]と同等ですx = *((int *)y + a * NUMBER_OF_COLUMNS + b);


ボーリングの詳細:

上記の(int *)キャストはy、その必要性が最初は直感的ではない可能性があるため、いくつかの説明に値します。なぜそこになければならないのかを理解するには、次のことを考慮してください。

  1. C/C++ の型付きポインター演算では、スカラーによる加算/減算/インクリメント/デクリメントの際に、型付きポインターの値 (アドレス) が型のサイズ (バイト単位) によって常に調整されます。

  2. 多次元配列宣言の基本型(要素型ではなく、変数型) は、最終次元よりも 1 つ少ない次元の配列型です。

これらの後者 (#2) を固めるには、実際に例が必要です。以下では、変数ar1ar2は同等の宣言です。

int ar1[5][5]; // an array of 5 rows of 5 ints.

typedef int Int5Array[5];  // type is an array of 5 ints
Int5Array ar2[5];          // an array of 5 Int5Arrays.

今度はポインター演算部分です。型付き構造体ポインタを構造体のサイズ (バイト単位) だけ進めることができるのと同様に、配列の全次元を飛び越えることができます。上記で ar2 を宣言した多次元配列を考えると、これは理解しやすくなります。

int (*arptr)[5] = ar1; // first row, address of ar1[0][0].
++arptr;               // second row, address of ar[1][0].

これはすべて、裸のポインターでなくなります。

int *ptr = ar1; // first row, address of ar1[0][0].
++ptr;          // first row, address of ar1[0][1].

したがって、2 次元配列のポインター演算を実行する場合、多次元配列の要素を取得する際に次の方法は機能しません[2][2]

#define NUMBER_OF_COLUMNS   5
int y[5][NUMBER_OF_COLUMNS];
int x = *(y + 2 * NUMBER_OF_COLUMNS + 2); // WRONG

yそれが配列の配列であることを思い出すと、その理由は明らかです(宣言的に言えば)。スケーラー(2*5 + 2)yに追加するポインター演算は 12を追加し、それによって と同等のアドレスを計算してアドレス指定しますが&(y[12])、これは明らかに正しくなく、実際、コンパイル時に太った警告をスローするか、完全にコンパイルに失敗します。これは、式のキャスト(int*)yと結果の型が int への裸のポインターに基づいていることで回避されます。

#define NUMBER_OF_COLUMNS   5
int y[5][NUMBER_OF_COLUMNS];
int x = *((int *)y + 2 * NUMBER_OF_COLUMNS + 2); // Right!
于 2012-11-25T18:54:43.647 に答える
25

テーブル

C の 2D 配列は連続した一連の行です (Pascal とは異なります)。
4 行 5 列の整数のテーブルを作成すると、次のようになります。 5*4 の整数テーブル。

要素に到達する

次の方法で要素に到達できます。

int element = table[row-1][column-1];

しかし、次のコードでもこれを行うことができます。

int element = *(*(table+row-1)+column-1);

これらの例rowcolumnは、1 からカウントされます。これが -1 の理由です。
次のコードでは、両方の手法が正しいことをテストできます。この場合、行と列を 0 から数えます。

#include <stdio.h>
#include <stdlib.h>
#define HEIGHT 4
#define WIDTH 5

int main()
{
    int table[HEIGHT][WIDTH] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
    int row = 2;
    int column = 2;
    int a = *(*(table+row)+column);
    printf("%d\n",a);//13
    printf("%d\n",table[row][column]);//13
    return 0;
}

説明

これは double poiner 演算であるためtable、最初の行を*table指し、最初の要素を指します。逆参照すると**table、最初の要素の値が返されます。*table次の例では、とtableが同じメモリ アドレスを指していることがわかります。

printf("%d\n",table);//2293476
printf("%d\n",*table);//2293476
printf("%d\n",**table);//1

メモリ内では、テーブルのすべての行が相互に続いています。table必要な要素がテーブル内にある行番号を追加すると、最初の行を指すため、その行を指すポインターを取得します。この場合*(table+row)、指定された行の最初の要素へのアドレスが含まれます。のように列番号を追加するだけ*(table+row)+columnで、指定された行と列の要素のアドレスを取得できます。これを逆参照すると、この要素の正確な値が得られます。
したがって、行と列をゼロから数えると、次のようにテーブルから要素を取得できます。

int element = *(*(table+row)+column);

記憶の中

メモリ内のテーブル。

于 2012-11-25T19:29:23.100 に答える
20

2D配列は、1D配列の配列と見なされます。つまり、2D配列の各行は1D配列です。したがって、2D配列が与えられるとA

int A[m][n].

一般に、

A[i][j] = *(A[i]+j) 

また

A[i] = *(A+i)

それで、

A[i][j] = *(A[i]+j) = * ( *(A+i)+j).
于 2012-11-25T19:01:20.923 に答える
6

以前の回答はすでに非常によく説明されています。私の理解に従ってポインター式をリストし、それらをarr[i][j]形式と比較します。

2 次元配列のポインター式:
    配列名自体は最初のサブ配列へのポインタです。

    到着:
        最初のサブ配列の最初の要素ではなく、最初のサブ配列へのポインターになります
        配列、配列とポインタの関係に応じて、それも表現します
        配列自体、

    arr+1 :
        最初のサブ配列の 2 番目の要素ではなく、2 番目のサブ配列へのポインターになります
        配列、

    *(arr+1) :
        2 番目のサブ配列の最初の要素へのポインターになります。
        配列とポインタの関係により、秒も表すサブ配列、 arr[1]
        と同じ、

    *(arr+1)+2 :
        2 番目のサブ配列の 3 番目の要素へのポインターになります。

    *(*(arr+1)+2) :
        2 番目のサブ配列の 3 番目の要素の値を取得します。arr[1][2]
        と同じ、

二次元配列と同様に、多次元配列も同様の表現をしています。

于 2014-10-16T08:19:52.390 に答える
2

ポインターでアクセスする実用的な方法。

typedef struct
{
    int  Array[13][2];
} t2DArray;

t2DArray TwoDArray =
{
   { {12,5},{4,8},{3,6},{7,9},{3,2},{3,3},{3,4},{3,5},{3,6},{3,7},{4,0},{5,0},{5,1} }
};

t2DArray *GetArray;

int main()
{
    GetArray = &TwoDArray;
    printf("\n %d\n %d\n %d\n %d\n %d\n %d\n",
    GetArray->Array[0][0], 
    GetArray->Array[0][1], 
    GetArray->Array[1][0], 
    GetArray->Array[1][1], 
    GetArray->Array[2][0], 
    GetArray->Array[2][1]);

    getchar();
    return 0;
}

アウト

12 5 4 8 3 6

于 2018-07-15T21:38:18.807 に答える