偏微分方程式を解いてるとごちゃごちゃと中間変数が出てきて泣きたくなるので、構造体にまとめましたとさという話です。例えば、衝撃波感の問題を解くのに特性曲線なり、CIPなり、Roeなりで解くとしてごっちゃりと変なのが出て来る訳です。未知変数をRho、U、Pとして、その導関数とか、それぞれに対応する流束とか出てきて泣ける。
ので、構造体で定義します。
構造体の基本的な使い方
例えば、構造体Varsというのを、
struct Vars { double U [LL]; double P [LL]: };
とか定義して、main関数の中で、Vars型の構造体Qを、
int main () { struct Vars Q; }
とか定義まします。
これは、行列Qの元にUとPがあるみたいなのに俺の中では対応していて、Q=(U, P)みたいな感じです。つまり、Qというベクトルの中にUとPという変数が入ってる感じです。
なので、Vars型の構造体Qの中Uの値を扱うという手順を踏みます。で、実際に、Qの中のUは、
for (i = 0; i < LL; i++) { Q.U[i] = i; printf ("U[%d] = %lf?n", i, Q.U[i]); }
みたいにして、構造体Qの中のUは.を使って参照するみたいです。どうやらQ.Uで構造体Qの先頭アドレスからUだけ下がったところにある値を参照するということらしい。あと、この記法はC++のクラスとかなんとかそういうのに似ている気がする。
typedef
一々、
struct Vars { double U [LL]; double P [LL]; }; int main () { struct Vars Q, Qx, Qtmp, Qxtmp; return 0; }
とかすると格好悪いので、typedefを使います。
例えば、const staticとかいう風に、静的変数を定数にして、絶対これは変わらないようなのをメモリ上に置きたくて、const staticとかかかないで、CSとかしたいときは、
typedef const static CS; int main () { CS PI = 3.14159265 ... }
とかするらしいです。
同じように、Varsという構造体の型を、
typedef Vars { double U [LL]; double P [LL]; } VARS; int main () { VARS Q, Qx; ... }
とかすることができて、構造体をあからさまに使ってるのを「隠す」ことができて良い感じです。
構造体を関数に渡す
どうやら構造体を丸ごと関数にコピーする方法と、構造体のアドレスを渡す方法があるらしい。
でもまるごと関数にコピーすると氏ぬ程時間がかかるので、参照渡しにします。ので、ポインタを使うらしい。ポインタについては触り程度は知ってるつもり。
なので、例えばQというVars型の構造体を関数に渡すには、Vars型の構造体のポインタQを定義して、それを関数に渡せばいいらしい。そして、引数も、Vars型の構造体へのポインタQを使うということかね。
例えば、Qの導関数Qxを求める関数をdQdxとして、
typedef Vars { // 構造体Varsの宣言 double U [LL]; double P [LL]]; } VARS; void dQdx (VARS *Q, VARS *QX, double dx); // dQdxのプロとライプ宣言 int main () { VARS Q, Qx; // Vars型の構造体QとQxの宣言 double dx = 0.01; dQdx (&Q, &Qx, dx); // dQdxに構造体Qと構造体Qxの先頭アドレスを渡す return 0; } void dQdx (VARS *Q, VARS *QX, double dx) { // VARS型へのポインタQとQxを受け取ってどうのとか int i; for (i = 1; i < LL-1; i++) { Qx -> U[i] = 0.5*(Q -> U[i+1] - Q -> U[i-1])/dx; Qx -> P[i] = 0.5*(Q -> P[i+1] - Q -> P[i-1])/dx; } }
ということになります。
んと、先頭アドレスを渡して、そっから下に続いてるデータは関数の中で隙に料理してくれってことですね。
typedef Vars { // 構造体Varsの宣言 double U [LL]; double P [LL]]; } VARS; void dQdx (VARS *Q, VARS *QX, double dx); // dQdxのプロとライプ宣言 int main () { VARS *Q, *Qx; // Vars型の構造体へのポインタQとQxの宣言 double dx = 0.01; dQdx (Q, Qx, dx); // dQdxに構造体Qと構造体Qxの先頭アドレスを渡す return 0; } void dQdx (VARS *Q, VARS *QX, double dx) { // VARS型へのポインタQとQxを受け取ってどうのとか int i; for (i = 1; i < LL-1; i++) { Qx -> U[i] = 0.5*(Q -> U[i+1] - Q -> U[i-1])/dx; Qx -> P[i] = 0.5*(Q -> P[i+1] - Q -> P[i-1])/dx; } }
あと、->は構造体の中の要素を参照するときに使う演算子で、構造体へのポインタを使うときはこれを使えばいいらしいということらしい。というか、あれだ、.は構造体の中の要素のアドレスを絶対的に指定して、->は相対的に指定するらしいです。ポインタだからというわけではなくて、ポインタというものの性質からこうなるらしい。分かるような分からないような微妙な感じである。