1

私は固定幅の座標系を持っています

#define gridSize 101
int _map[gridSize][gridSize];

-50 から 50 の範囲の特定の xy 座標の値を取得するので、たとえばmap[0][0]を指す縦座標の原点としてマップを呼び出したいと思います_map[51][51]。つまり、ソースから xy の値を取得し、それをマップに追加したい場合は、

map[x][y] = value

そして、実際に値を取得するのは

_map[51+x][51+y] = value

したがって、ポインターを作成する必要がありますが、多次元配列でそれを行う方法がわかりません。

#define gridSize 101 // must be an odd number for origin of ordinates in center
#define gridSizeCenter = (int)(gridSize/2)+1;
int _map[gridSize][gridSize];
int map[gridSize][gridSize];
map = &_map[gridSizeCenter][gridSizeCenter]; // wont work

コードの最後の行が間違っています。どうすれば正しくできますか?

4

3 に答える 3

1

そんなことはできません。_map最善の解決策は、おそらく変数にアクセスする一連の関数を用意することです。何かのようなもの:

void set_map_value(int map[][gridSize], const int value, const int x, const int y)
{
    map[x + 51][y + 51] = value;
}

int get_map_value(int map[][gridSize], const int x, const int y)
{
    return map[x + 51][y + 51];
}

関数を使用すると、型チェックが可能になり、座標の範囲チェックも可能になります。


思い通りにできない理由の 1 つと、コンパイル エラーの理由の 1 つは、型に互換性がないことです。

もう 1 つの理由は、配列に負のインデックスを実際に含めることができないことです。整数-1は と同じであることに注意してください0xffffffff。つまり、4294967295これは配列の範囲をはるかに超えています

于 2012-06-15T09:54:01.603 に答える
1

はい、できます!

配列でこれを行うことはできないと思いますが、配列要素へのポインタで行うことができます。

ただし、非常に正当な理由がない限り、これは行いません。負のインデックス可能なポインターは、コードを読んでいる人が期待するものではないため、誤って誤用するのは簡単です。明確にするために、非常に高速である必要がない限り、関数ベースのソリューションを使用したほうがよい場合があります。

それはさておき、やりましょう!

あなたの試みから、配列とポインタについて混乱しているようです。それらは同じものではないことに注意してください。

現在、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 次元配列と変わりませんが、デバッグ時には注意が必要です。

于 2012-06-15T13:30:10.477 に答える
0

このソリューションを使用できます

#define gridSize 101 // must be an odd number for origin of ordinates in center
#define gridSizeCenter gridSize/2 +1

int main (int argc, char *argv[]) {

    int _map[gridSize][gridSize];
#define MAP(A,B) _map[A+gridSizeCenter][B+gridSizeCenter]
    MAP(-1,-1) = 5;
    MAP(0,0) = 6;
    printf ("MAP(0,0) = %d\r\nMAP(-1,-1) = %d\r\n",MAP(0,0),MAP(-1,-1));
    return 0;
}
于 2012-06-15T10:51:35.437 に答える