1. ホーム
  2. c

[解決済み] 2次元配列へのポインタを作成する

2022-07-09 19:13:26

質問

静的な2次元配列へのポインタが必要です。これはどのように行われるのですか?

static uint8_t l_matrix[10][20];

void test(){
   uint8_t **matrix_ptr = l_matrix; //wrong idea 
}

などと、いろいろなエラーが出ます。

  • 警告: 互換性のないポインタ型からの代入
  • 添え字の値は配列でもポインタでもありません。
  • error: flexible array member の無効な使用

どのように解決するのですか?

ここでは、配列の最初の要素へのポインタを作成します。

uint8_t (*matrix_ptr)[20] = l_matrix;

typedefを用いると、よりすっきりした印象になります

typedef uint8_t array_of_20_uint8_t[20];
array_of_20_uint8_t *matrix_ptr = l_matrix;

そうすれば、また人生を楽しむことができます :)

matrix_ptr[0][1] = ...;

注意すべきは ポインタ/配列の世界 には注意してください。


編集

コメント欄が短すぎてそこではできないので、ここで他の回答のいくつかをレビューする。複数の選択肢が提案されましたが、それらがどのように動作するかは示されていませんでした。以下は、それらがどのように動作するかです。

uint8_t (*matrix_ptr)[][20] = l_matrix;

エラーを修正し、address-of 演算子を追加すると & を追加すると、次のスニペットのようになります。

uint8_t (*matrix_ptr)[][20] = &l_matrix;

次にその1つは、20 uint8_tのarray型の要素の不完全な配列型へのポインタを作成します。このポインタは配列の配列へのものなので、それにアクセスするには

(*matrix_ptr)[0][1] = ...;

また、不完全な配列へのポインタであるため はできません。 ショートカットとして

matrix_ptr[0][0][1] = ...;

なぜなら、インデックス付けは要素型のサイズが分かっている必要があるからです(インデックス付けはポインタへの整数の追加を意味するので、不完全な型では動作しません)。なお、これは C でしか動作しないことに注意してください。 T[] であり T[N] は互換性のある型です。C++には 互換性のある型 という概念がないため、そのコードは拒否されます。 T[]T[10] は異なるタイプです。


以下の代替案は全く機能しません。なぜなら、一次元配列として見たときの配列の要素型は ではなく uint8_t しかし uint8_t[20]

uint8_t *matrix_ptr = l_matrix; // fail


以下は良い代替案です。

uint8_t (*matrix_ptr)[10][20] = &l_matrix;

でアクセスすると

(*matrix_ptr)[0][1] = ...;
matrix_ptr[0][0][1] = ...; // also possible now

これは外側の次元のサイズを保持するという利点があります。そのため、その上にsizeofを適用することができます

sizeof (*matrix_ptr) == sizeof(uint8_t) * 10 * 20


配列のアイテムが連続的に格納されることを利用した、もう一つの回答があります。

uint8_t *matrix_ptr = l_matrix[0];

さて、この形式では2次元配列の最初の要素の要素にしかアクセスできません。つまり、以下の条件が成立します。

matrix_ptr[0] = ...; // valid
matrix_ptr[19] = ...; // valid

matrix_ptr[20] = ...; // undefined behavior
matrix_ptr[10*20-1] = ...; // undefined behavior

までしか動作しないことにお気づきでしょう。 10*20-1 までしか動作しませんが、エイリアス解析や他の積極的な最適化を行うと、コンパイラによってはそのコードが壊れるかもしれないという仮定をする可能性があります。とはいえ、この手法で失敗したコンパイラーに出会ったことはありませんし (ただし、実際のコードでこの手法を使ったことはありません)、C FAQ にもこの手法が (UB'ness についての警告とともに) 含まれており、配列タイプを変更できない場合、これはあなたを救う最後の選択肢になります :)