はい、できます!
配列でこれを行うことはできないと思いますが、配列要素へのポインタで行うことができます。
ただし、非常に正当な理由がない限り、これは行いません。負のインデックス可能なポインターは、コードを読んでいる人が期待するものではないため、誤って誤用するのは簡単です。明確にするために、非常に高速である必要がない限り、関数ベースのソリューションを使用したほうがよい場合があります。
それはさておき、やりましょう!
あなたの試みから、配列とポインタについて混乱しているようです。それらは同じものではないことに注意してください。
現在、C は負のインデックスの使用を妨げていません。これは、ポインターを使用している場合に意味があります。したがって、これを行うことができます:
int a[5];
int *b = a + 2; // or &a[2]
b[-2] // is a[0]
b[-1] // is a[1]
b[0] // ia a[2], etc
したがって、次のコードがうまくいくと思います。
#define GRIDSIZE 101
.....
int map_memory[GRIDSIZE][GRIDSIZE];
int *map_rows[GRIDSIZE];
int **map;
int i;
int gridMidPoint = GRIDSIZE / 2;
for(i = 0; i < GRIDSIZE; i++) {
map_rows[i] = &(map_memory[i][0]) + gridMidPoint;
}
map = map_rows + gridMidPoint;
次に、グリッド サイズを 101 にして、期待どおりに使用できます。
for(i = -50; i <= 50; i++) {
for(j = -50; j <= 50; j++) {
map[i][j] = i+j;
}
}
または、より一般的に:
for(i = -1 * gridMidPoint; i <= gridMidPoint; i++) {
for(j = -1 * gridMidPoint; j <= gridMidPoint; j++) {
map[i][j] = i+j;
}
}
両方の配列がスタック上に作成されるため、何も解放する必要はありません。
ここで何が起こっているのですか?分解してみましょう。まず、バッキング配列を作成します。
int map_memory[GRIDSIZE][GRIDSIZE];
次に、行として使用するポインターの配列が必要です。
int *map_rows[GRIDSIZE];
これらは、作成したばかりの 2 次元配列の配列の中央を指すため、ポインターである必要があります。
int gridMidPoint = GRIDSIZE / 2;
ここで中間点を計算します。ゼロの両側に同じ数の配列要素が必要であると想定しているため、例の +1 は必要ありません。
for(i = 0; i < GRIDSIZE; i++) {
map_rows[i] = &(map_memory[i][0]) + gridMidPoint;
}
このコードは、行配列の各要素を繰り返し処理し、その行が 2 次元配列の関連する行の中央を指すように設定します。次のように書くこともできます。
map_rows[i] = &map_memory[i][gridMidPoint];
しかし、個人的には、余分な括弧と追加のバージョンの方が読みやすいと思います。ポインターを使って異常なことをしている場合は、コードを次に読む人のために何が起こっているのかを正確に説明する必要があると思います。
最後に、map
ポインターが行の中央を指す必要があります。
map = map_rows + gridMidPoint;
これで完了です。
2 次元配列は、実際には連続したメモリの 1 つのブロックであることに注意してください。これは がmap[0][gridMidPoint+1]
と同じ場所であることを意味しmap[1][-1*gridMidPoint]
ます。これは実際には通常の 2 次元配列と変わりませんが、デバッグ時には注意が必要です。