1

私はデータベーステーブルレコードの構造に似たCの構造を持っています。selectを使用してテーブルをクエリすると、取得するレコードの数がわかりません。selectクエリから返されたすべてのレコードを構造体データ型の配列に格納したいと思います。

どちらの方法が最適ですか?

方法1:配列サイズを見つけて割り当てる

  1. まず、テーブルからselect count(*)を実行して、レコードの数を取得します
  2. 静的配列を割り当てる
  3. select * from tableを実行してから、各レコードを構造内のループに格納します。

方法2:単一のリンクリストを使用する

while ( records returned )
{
    create new node 
    store the record in node 
}

どの実装が最適ですか?

私の要件は、すべてのレコードが揃ったら、おそらくそれらのコピーか何かを作成することです。ただし、ランダムアクセスは必要なく、特定のレコードの検索は行いません。

ありがとう

4

7 に答える 7

3

そして、オプション#4を忘れました。固定サイズの配列を割り当てます。その配列がいっぱいになったら、別の配列を割り当てます。リンクされたリストでそれらをリンクするか、データ配列へのポインターを保持するより高いレベルの配列を持つことにより、配列を追跡できます。この 2 レベルのスキームは、ランダム アクセスが必要な場合に最適です。インデックスを 2 つの部分に分割するだけで済みます。

于 2009-01-01T16:53:06.727 に答える
1

'select count(*)'の問題は、呼び出しごとに値が変わる可能性があるため、「実際の」選択には、予想される数とは異なる数の項目が含まれることです。

最善の解決策はあなたの「2」だと思います。リンクリストの代わりに、私は個人的に配列を割り当てます(必要に応じて再割り当てします)。これは、増大する配列をサポートする言語(std::vector<myrecord>C ++やList<myrecord>C#など)では簡単です。

于 2009-01-01T16:41:40.743 に答える
1

オプション3を忘れましたが、もう少し複雑ですが、特定のケースに最適な場合があります。これは、C ++ std::vectorで通常行われる方法です。

任意の快適なサイズのアレイを割り当てます。その配列がいっぱいになったら、塗りつぶされた配列の1.5倍から2倍のサイズの新しい大きな配列を割り当て、塗りつぶされた配列をこの配列にコピーします。元のアレイを解放して、新しいアレイと交換します。泡立てて、すすぎ、繰り返します。

于 2009-01-01T16:49:33.787 に答える
0

リンクリストは、素晴らしくシンプルなオプションです。私はそれで行きます。増大する配列を好む場合は、DaveHansonのCInterfaces and Implementationsの一部として実装を見つけることができます。これは、ボーナスとしてリンクリストも提供します。

これは、アプリケーションの進化に伴って変更される可能性のある設計上の決定のように見えるので、適切なAPIの背後に表現を確実に隠す必要があります。これを行う方法がまだわからない場合は、Hansonのコードでいくつかの優れた例が示されます。

于 2009-01-02T05:06:24.140 に答える
0

配列またはリストを表すデータ構造を作成します。OO 言語を使用しているふりをして、必要なものすべてに対してアクセサーとコンストラクターを作成します。そのデータ構造内に配列を保持し、他の人が言ったように、配列がいっぱいになったら、2倍の大きさの新しい配列を割り当ててコピーします。アクセス用に定義したルーチンを介してのみ、構造体にアクセスしてください。

これは、Java や他の言語がこれを行う方法です。内部的には、これは Perl が C で実装されている方法でもあります。

私はあなたの最善の選択肢は、すでにこれを行うライブラリを探すことだと言いました...おそらく、この種のデータ構造のPerlのC実装を借りることができます. 私はあなたや私が最初からロールアップできるものよりもよくテストされていると確信しています. :)

于 2009-01-01T17:37:05.343 に答える
0
while(record = get_record()) {
  records++;
  records_array = (record_struct *) realloc(records_array, (sizeof record_struct)*records);
  *records_array[records - 1] = record;
}

これはあくまで一例です — 本番環境では realloc() を使用しないでください。

于 2009-01-01T19:57:20.363 に答える
0

なすべき批判はたくさんあります。

  1. 静的配列についてはまったく話していません-静的配列は、コンパイル時に固定された事前定義されたサイズであり、ソースファイルに対してローカルまたは関数に対してローカルです。あなたは動的に割り当てられた配列について話している。

  2. レコードのサイズやレコードの数、またその下にあるデータベースがどれほど動的であるか (つまり、実行中に他のプロセスがデータを変更する可能性がある) を示すことはありません。サイジング情報はそれほど重要ではありませんが、もう 1 つの要因が重要です。何らかのレポートを作成している場合は、データをメモリにフェッチしても問題ありません。データベースを変更するつもりはなく、データは正確なスナップショットです。ただし、レコードを変更している間に他の人がレコードを変更している可能性がある場合、アウトライン ソリューションは、他の人の更新を失う方法の主な例です。それは悪いことです!

  3. 一度にメモリ内のすべてのデータが必要なのはなぜですか? サイズの制約を無視すると、関連する各レコードを正しい順序で 1 回処理することと比較して、その利点は正確には何ですか? ご覧のとおり、DBMS は、関連するレコード (WHERE 句) と関連するデータ (SELECT リスト) を選択できるようにするために多くの労力を費やし、シーケンス (ORDER BY 句) を指定できるようにし、可能な限り最高の並べ替えシステムを備えています。余裕があります(あなたまたは私が生産する可能性が高いものよりも優れています).

  4. 配列をチャンクで割り当てる場合は、2 次動作に注意してください。再割り当てするたびに、古いメモリを新しい場所にコピーする必要がある可能性が十分にあります。これにより、メモリが断片化されます (古い場所は再利用できますが、定義上、小さすぎて再利用できません)。Mark Ransom は、世界で最も単純なスキームではありません (ただし、私が言及した 2 次動作を回避します)。もちろん、一連の適切な関数によってそれを抽象化することができます (またそうするでしょう)。

  5. バルク フェッチ (Mark Ransom も言及) も便利です。余分なコピーを行う必要がないように、一括フェッチがフェッチする配列を事前に割り当てたいと思うでしょう。ただし、これは直線的な動作であるため、それほど深刻ではありません。

于 2009-01-01T17:14:54.203 に答える