web-dev-qa-db-ja.com

構造の配列を反復する方法

私のアプリケーションでは、構造体の配列を使用しており、配列を反復処理する必要があります。それを行う適切な方法は何ですか?アレイの最後に達したかどうかを確認するにはどうすればよいですか?

// structure
struct MyData {
  int count;
  char name[20];
  float average;
}

私はこのように繰り返してみましたが、アプリケーションがクラッシュします:

struct MyData data[2] = { {3, "name1", 1.0}, {5, "name2", 2.5} };
struct MyData* ptr = data;

while (*ptr != NULL) {
  // print the contents, works ok for 2 elements

  ptr++; // increment the pointer
}
12
Dariusz

構造体の配列はどのように割り当てられますか

あなたの場合、_MyData[2]_配列はメモリ内では次のようになります。

_| count | name | average | count | name | average |
^ -- your ptr points here 
_

これは、サイズが3 * sizeof (struct MyData)の単一の連続スペースです。

_ptr++_操作を実行すると、ポインタは配列の次の構造に移動します。つまり、単一の_struct MyData_のサイズが考慮されます。

_| count | name | average | count | name | average |
                         ^ -- after ptr++ your ptr points here
_

別の_ptr++_の後、ポインタはメモリを指します直後配列。

_| count | name | average | count | name | average | 
                                                  ^ -- another ptr++ and your ptr points here
_

ptrポインターを逆参照すると、まだ使用されていない、または割り当てられていないメモリにアクセスします。これは未定義の動作であり、アプリケーションがクラッシュするためです。

反復する方法は?

それを行うにはいくつかの方法があります。すべての方法がすべての場合に適用できるわけではないことに注意してください。

シンプル

多くの場合、私たちは単純に配列のサイズを知っています。その後、通常のforループを使用して、コンテンツを反復処理できます。

_int len = 2;
struct MyData data[len] = { {3, "name1", 1.0}, {5, "name2", 2.5} };
struct MyData* ptr = data;
for (int i=0; i<2; i++, ptr++ ) {
   // do your thing with the ptr
   // and note that ptr gets increased inside for
}
_

sizeofを使用して配列の長さを決定する

_struct MyData data[2] = { {3, "name1", 1.0}, {5, "name2", 2.5} };
struct MyData* ptr = data;
struct MyData* endPtr = data + sizeof(data)/sizeof(data[0]);
while ( ptr < endPtr ){
   // do your thing with the ptr
   ptr++;
}
_

sizeof(data)/sizeof(data[0])は、要素の量を計算します。配列の合計サイズを取得し、それを単一の要素のサイズで割ります。

この方法には欠点があります。配列がポインタとして宣言されている場合は使用できません!たとえば、配列をパラメータとして関数に渡すと、通常はポインタに変換されます。その後、配列のサイズを特定できません。

20
Dariusz

配列のサイズを制御できず、それを要求することさえできない場合は、MyDataの配列ではなくpointersからMyDataへ。その場合、NULL値を持つガードを格納するには、配列を1スロット長くする必要があります。

イテレーションは、例として書いたイテレーションのようになります。

// N is the number of MyData instances you have
MyData* vData[N+1];
// vData[i] is filled, and vData[N] = NULL

// ...

MyData* vPtr = vData[0];
while(vPtr) {
    // ...
}

ただし、これには配列のタイプをMyData[]からMyData*[]に変更することが含まれます。できない場合は、Dariuszの回答に従ってください。

1
Oragon Efreet