a がメモリ内でどのように見えるかは理解できますvoid**が、それを正しく使用しているかどうか疑問に思っています。以下に説明する内容に根本的な欠陥はありますか? たとえば、「自分には合っている」とは言えますが、何らかの方法で悪い/移植性のないコードを作成していませんか?
だから私は小惑星のクローンを持っています。弾丸を発射できるエンティティは、プレイヤー ( SHIP *player_1、SHIP *player_2) と UFO ( UFO *ufo) の 3 つです。弾丸が発射されたとき、誰が弾丸を発射したかを知ることが重要です。プレーヤーの場合、何かに当たったときにスコアを増やす必要があります。したがって、箇条書きには、それが属するエンティティの種類 ( owner_type) と、所有者への直接のポインタ( ) が格納されますowner。
enum ShipType
{
SHIP_PLAYER,
SHIP_UFO
};
typedef struct Bullet
{
// ...other properties
enum ShipType owner_type;
void **owner;
} BULLET;
次に、プレイヤーがボタンを押すか、UFO がターゲットを検出すると、次の関数のいずれかが呼び出されます。
void ship_fire(SHIP **shipp)
{
BULLET *bullet = calloc(1, sizeof(BULLET));
bullet->owner_type = SHIP_PLAYER;
bullet->owner = (void**)shipp;
// do other things
}
void ufo_fire(UFO **ufop)
{
BULLET *bullet = calloc(1, sizeof(BULLET));
bullet->owner_type = SHIP_UFO;
bullet->owner = (void**)ufop;
// do other things
}
...たとえば、次のように呼び出すことができます。
ship_fire(&player_1);
最後に、弾丸がターゲット (小惑星など) に命中すると、所有者を逆参照します。船の場合は、その場でスコアをインクリメントできます。
void hit_asteroid(ASTEROID *ast, BULLET *bullet)
{
SHIP *ship_owner;
if (bullet->owner_type == SHIP_PLAYER && *bullet->owner != NULL)
{
ship_owner = (SHIP*)*bullet->owner;
ship_owner->score += 1000;
}
}
それは合理的なアプローチだと思いますか?私が言うように、それは私にとってはうまくいきますが、C の経験は数か月しかありません。
最後の注意: なぜ a のvoid*代わりに a を使用しないのvoid**ですか? ダングリングポインターを避けたいからです。言い換えれば、player_1死んで解放されたが、弾丸は進み続けて小惑星に衝突したとします。しかない場合void*、関数はそれが割り当て解除されたメモリを指してhit_asteroidいることを知る方法がありません。bullet->ownerしかし、 を使用するとvoid**、それが NULL かどうかを有効に確認できます。player_1が NULL の場合は、これ*bullet->ownerも NULL になります。
編集:これまでのすべての回答者は、(たとえば、ベースオブジェクトを静的に割り当てるだけで) ダングリングポインターの問題を回避できるため、ここではおそらく void** を使用する必要はないことに同意しています。それらは正しいので、リファクタリングします。しかし、メモリ割り当て/キャストなどの点で何かを壊す可能性のある方法で void** を使用したかどうかを知りたいと思っています。しかし、誰も手を空中に投げ出して欠陥を宣言しなかったとしたら、少なくとも技術的には機能するものに似ていると思います.
ありがとう!