1. ホーム
  2. c

[解決済み] C 動的に成長するアレイ

2022-03-04 03:58:47

質問

ゲーム内のエンティティのquot;raw"リストを読み込むプログラムがあるのですが、不特定多数のエンティティのインデックス番号(int)を持つ配列を作り、いろいろな処理をしようと思っています。そのインデックスを保持するために、あまりメモリやCPUを使わないようにしたいのですが...。

私がこれまで使ってきた手っ取り早い解決策は、メイン処理関数(ローカルフォーカス)の中で、ゲームエンティティの最大サイズを持つ配列と、リストにいくつ追加されたかを追跡するための別の整数を宣言することです。 これは満足のいくものではありません。すべてのリストが3000以上の配列を保持するので、それほど多くはありませんが、さまざまな機能で6-7個のリストにこのソリューションを使用する可能性があるので、無駄のように感じられます。

これを実現するためのC言語(C++やC#ではない)特有の解決策は見つかっていません。ポインターを使うことはできますが、(それが唯一の可能な方法でない限り)それを使うのは少し怖いです。

配列はローカル関数スコープを離れない(関数に渡され、その後破棄される)ので、状況が変わるかもしれません。

ポインタが唯一の解決策である場合、リークを回避するためにどのようにポインタを追跡すればよいですか?

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

<ブロッククオート

ポインターは使えるのですが、ちょっと怖いんです。

動的配列が必要な場合、ポインターを逃れることはできない。でも、どうして怖いんですか?彼らは(あなたが注意する限りは、ですが)噛まないでしょう。C言語には組み込みの動的配列がないから、自分で書くしかない。C++では、組み込みの std::vector クラスがあります。C#やその他多くの高級言語にも、動的配列を管理する類似のクラスがあります。

ほとんどの動的配列の実装は、ある(小さな)デフォルトサイズの配列から始めて、新しい要素を追加するときにスペースが足りなくなったら、配列のサイズを倍にすることで動作します。以下の例でわかるように、これはそれほど難しいことではありません。(簡潔さのため、安全性の確認は省略しています)

typedef struct {
  int *array;
  size_t used;
  size_t size;
} Array;

void initArray(Array *a, size_t initialSize) {
  a->array = malloc(initialSize * sizeof(int));
  a->used = 0;
  a->size = initialSize;
}

void insertArray(Array *a, int element) {
  // a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
  // Therefore a->used can go up to a->size 
  if (a->used == a->size) {
    a->size *= 2;
    a->array = realloc(a->array, a->size * sizeof(int));
  }
  a->array[a->used++] = element;
}

void freeArray(Array *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
}

使い方はいたってシンプル。

Array a;
int i;

initArray(&a, 5);  // initially 5 elements
for (i = 0; i < 100; i++)
  insertArray(&a, i);  // automatically resizes as necessary
printf("%d\n", a.array[9]);  // print 10th element
printf("%d\n", a.used);  // print number of elements
freeArray(&a);