6

オペレーティング システムのコースですぐに C の使用を開始する予定です。C の使用に関するベスト プラクティスを読んで、後で頭痛が軽減されるようにしています。

これは、アレイが台無しになりやすいため、常にアレイに関する最初の質問の 1 つでした。

配列とその長さを構造体に含む関連変数をバンドルするのは一般的な方法ですか?

私は本でそれを見たことがなく、通常、それらは常に2つを別々に保持するか、 sizeof(array[]/array[1]) のようなものを使用します。

しかし、この 2 つを構造体にラップすると、値と参照の両方で構造体を渡すことができます。これは、ポインターを使用しない限り、配列では実際に行うことができません。その場合、配列の長さを再度追跡する必要があります。 .

私はCを使い始めているので、上記はひどく間違っている可能性があります.私はまだ学生です.

乾杯、カイ。

4

11 に答える 11

6

はい、これは C での優れた実践です。関連する値を包含構造にラップすることは完全に論理的です。

私はさらに先に進みます。また、これらの値を直接変更しないことも目的に役立ちます。代わりに、構造体内でこれらの値にペアとして作用する関数を記述して、長さを変更し、データを変更します。そうすれば、不変チェックを追加して、テストを非常に簡単にすることができます。

于 2009-03-19T13:15:53.980 に答える
4

確かに、あなたはそれを行うことができます。これをベスト プラクティスと呼ぶかどうかはわかりませんが、C のかなり初歩的な配列をもう少し扱いやすくすることは確かに良い考えです。動的配列が必要な場合は、簿記を一緒に行うために必要なさまざまなフィールドをグループ化することがほぼ必須です。

その場合、2 つのサイズがある場合があります。1 つは現在のサイズで、もう 1 つは割り当て済みです。これは、多少のメモリ オーバーヘッドを払って、ある程度の速度と引き換えに少ない割り当てを行うというトレードオフです。

多くの場合、配列はローカルでのみ使用され、静的なサイズですsizeof。そのため、要素の数を決定するのに演算子が非常に便利です。ちなみに、あなたの構文は少しずれていますが、通常は次のようになります。

int array[4711];
int i;

for(i = 0; i < sizeof array / sizeof *array; i++)
{
  /* Do stuff with each element. */
}

は関数ではないことに注意してくださいsizeof。括弧は必ずしも必要ではありません。

編集:あなたが説明したものとまったく同じラッピングの実際の例の1つは、glibによって提供されるGArrayタイプです。宣言のユーザーに表示される部分は、まさにあなたが記述したものです。

typedef struct {
  gchar *data;
  guint len;
} GArray;

プログラムは、可能な限り提供された API を使用して配列にアクセスすることが期待されており、これらのフィールドを直接 poke することはありません。

于 2009-03-19T13:14:45.450 に答える
4

3つの方法があります。

  1. 静的配列 (動的に割り当てられず、ポインターとして渡されない) の場合、サイズはコンパイル時に認識されるため、次sizeofのように演算子を使用できます。sizeof(array)/sizeof(array[0])
  2. null で終わる文字列のように、ターミネータ (通常の配列値として使用できない最後の配列要素の特別な値) を使用します
  3. 構造体メンバーまたは独立変数のいずれかとして、個別の値を使用します。配列を操作するすべての標準関数は個別のサイズ変数を取るため、実際には問題ではありませんが、配列ポインターとサイズを 1 つの構造体に結合すると、コードの読みやすさが向上します。独自の関数のインターフェイスをよりクリーンにするために使用することをお勧めします。構造体を値で渡す場合、呼び出された関数は配列を変更できますが、サイズ変数を変更できないため、構造体ポインターを渡す方が良いオプションになることに注意してください。
于 2009-03-19T13:21:48.257 に答える
2

それは良い習慣だと思います。実際、C++ ではそれを標準ライブラリに入れて と呼ぶだけで十分ですvector。C++ フォーラムで配列について話すときはいつでも、vector代わりに使用するようにという回答が殺到します。

于 2009-03-19T14:05:58.260 に答える
2

パブリック API の場合は、配列とサイズの値を分けて使用します。それが、私が知っているほとんどの(すべてではないにしても)Cライブラリで処理される方法です。内部でどのように処理するかは、完全にあなた次第です。したがって、構造体に加えて、トリッキーな部分を実行するいくつかのヘルパー関数/マクロを使用することをお勧めします。アイテムを挿入したり削除したりする方法を再考するのはいつも頭が痛いので、問題の良い原因です. それを一度かつ一般的に解決すると、最初からバグを見つけるのに役立ちます。動的配列と汎用配列の優れた実装はkvecです。

于 2009-03-19T13:41:26.370 に答える
1

それを行うことに問題はないと思いますが、通常行われない理由は、そのような構造によって発生するオーバーヘッドのためだと思います。ほとんどの C は、パフォーマンス上の理由からベアメタル コードであるため、抽象化はしばしば回避されます。

于 2009-03-19T13:14:37.150 に答える
1

本でもあまり見たことがありませんが、しばらく前から同じことをやっています。それらを一緒に「パッケージ化」することは理にかなっているようです。たとえば、メソッドから割り当てられた配列を返す必要がある場合に特に便利です。

于 2009-03-19T13:17:24.180 に答える
1

静的配列を使用する場合、sizeof 演算子を使用して配列のサイズにアクセスできます。構造体に入れる場合は、値、参照、およびポインターによって関数に渡すことができます。引数の参照渡しとポインタ渡しは、アセンブリ レベルでは同じです (ほぼ確実です)。

しかし、動的配列を使用すると、コンパイル時に配列のサイズがわかりません。したがって、この値を構造体に格納できますが、配列へのポインターのみを構造体に格納することもできます。

struct Foo {
  int *myarray;
  int size;
};

したがって、この構造体を値で渡すことができますが、実際に行うことは、int (配列へのポインター) と int (配列のサイズ) へのポインターを渡すことです。

私の意見では、それはあまり役に立ちません。プラスの唯一の点は、サイズと配列を 1 つの場所に格納し、配列のサイズを簡単に取得できることです。多くの動的配列を使用する場合は、この方法で行うことができます。ただし、使用する配列が少ない場合は、構造体を使用しない方が簡単です。

于 2009-03-19T13:40:48.697 に答える
0

私はそれがそのように行われたのを見たことがありませんが、OS レベルの作業を 10 年以上行っていません... :-) 一見すると合理的なアプローチのように思えます。唯一の懸念は、サイズが何らかの形で正確であることを確認することです...必要に応じて計算することには、その懸念はありません。

于 2009-03-19T13:16:17.210 に答える
0

配列の長さ(バイト単位、つまり要素数ではない)を計算できることを考慮し、コンパイラは sizeof() 呼び出しを実際の値に置き換えます(関数ではないため、呼び出しはコンパイラによって置き換えられますそれが「返す」値)、構造体でラップする唯一の理由は、読みやすさのためです。

これは一般的な方法ではありません。コードを見た人は、配列サイズだけでなく、長さフィールドが何らかの特別な値であると想定するでしょう。それはあなたの提案に潜む危険なので、適切にコメントするように注意する必要があります.

于 2009-03-19T13:19:06.203 に答える
0

あなたの質問のこの部分は逆だと思います:

「しかし、2 つを 1 つの構造体にラップすることで、構造体を値と参照の両方で渡すことができます。これは、ポインターを使用しない限り、配列では実際に行うことができません。その場合、再び配列を追跡する必要があります。長さ。"

配列を渡すときにポインターを使用するのがデフォルトの動作です。配列全体を値で渡すという点では、何も購入しません。配列をポインターに減衰させるのではなく、配列全体をコピーする場合は、配列を構造体でラップする必要があります。詳細については、この回答を参照してください。

配列を値で再帰関数に渡すことは可能ですか?

また、配列の特別な動作については次のとおりです。

http://denniskubes.com/2012/08/20/is-c-pass-by-value-or-reference/

于 2014-12-14T17:51:06.650 に答える