問題: 2D配列にファイルの値を入力する関数をCで作成しようとしているとします。ファイルには、行(レコード)に配置された値が含まれ、各行にはいくつかのフィールドが含まれます。この関数は、2D配列へのポインターとファイルのアドレスを受け取り、配列に入力する必要があります。重要なことに、この関数は、レコードごとに存在するフィールドの数に関係なく機能する必要があります。たとえば、あるプログラムでは、関数を呼び出して、レコードごとに4つのフィールドがあるファイルから値を読み取ることができます。
int array_of_values[MAX_NUMBER_OF_RECORDS][4];
fill_in_array(array_of_values, "spacetime.csv");
別のプログラムでは、レコードごとに11個のフィールドがある場合に、値を入力することができます。
int array_of_values[MAX_NUMBER_OF_RECORDS][11];
fill_in_array(array_of_values, "M-theory.csv");
残念ながら、これを行おうとすると、Cが多次元配列を処理する方法に失敗します。多次元配列は、Cでは配列へのポインターの配列としてではなく、1つの長い1次元配列として実装されます。これは、関数が配列からデータを読み取るために、配列の幅を知る必要があることを意味します。
したがって、次の関数定義ではエラーが発生します。
void fill_in_array(int array_of_values[MAX_NUMBER_OF_RECORDS][], char *path)
[次の点で問題ないことに注意してください。
void fill_in_array(int array_of_values[][MAX_NUMBER_OF_RECORDS], char *path)
コンパイラは最初の次元のインデックスを知る必要はありませんが、これは許可されていないと仮定します(たとえば、関数がのような個々のレコードをいじくり回す必要がある場合array_of_values[1]
)。]
これが私のプログラムで到達したポイントです。自分自身を提示する2つの解決策があります:
- 関数を強制的に固定数のフィールドで動作させます。私は明らかにこれをしたくないのですが、たとえば、定数
MAX_NUMBER_OF_FIELDS
を宣言して未使用のフィールドを空のままにすることができます。 fill_in_array
関数が配列ではなくポインターを取り込んで、フィールドを含むIliffeベクトルを動的に割り当てるようにします。これは魅力的なアイデアです(レコード/フィールドの最大数を宣言する必要がなくなるためですが、フィールドの配列を解放する関数を作成する(そして使用することを忘れないでください!)必要があることも意味します。
もう1つのアイデアがあります。これは、関数の宣言を次のように変更することです。
void fill_in_array(int **array_of_values, int number_of_fields, char *path)
(ここでnumber_of_fields
は、レコードごとのフィールド数を指しているため、と呼ぶ場合がありますfill_in_array(array_of_values, 4, "spacetime.csv");
。
array_of_values
パラメータは明示的な配列ではなく、ポインタであることに注意してください。通常、2D配列を指すようにダブルポインタを割り当てた場合、結果は無意味になります。number_of_fields
私の考えでは、関数が。のような式の処理方法を認識できるように、パラメーターを使用できる可能性がありますarray_of_values[i][j]
。
原則として、これはかなり簡単なはずです。実際、a
が2D配列の場合、次のa[i][j]
ように定義されます。
*(a + (i * n) + j)
ここn
で、は配列の長さです。したがって、のすべての出現をで置き換え、すべての出現をで置き換えることarray_of_values[i][j]
が*(array_of_values + (i * number_of_fields) + j)
できarray_of_values[i]
ますarray_of_values + (i * number_of_fields)
。ただし、このコードは非常に読みにくいでしょう。number_of_fields
インデックス表記を使用して配列の要素にアクセスできるように、配列の幅が広いことをコンパイラに通知する方法はありますか?