質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

2回答

931閲覧

C言語 コードの理解を助けてほしいです

Tubasa1995

総合スコア83

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2021/09/03 12:56

現在オープンソースの「Code Saturne」というものを利用しています。その中でC言語で書かれた関数を理解する必要があるの、C言語の勉強を始めたばかりです。一通り基礎を通してやったのですが、これまでpythonなどを軽く触っただけの経験しかなく、いざコードのポインタや構造体などを見ると頭が混乱してしまいます。本来ここはコードの修正点などを教えてもらう場所なことはわかっていますが、教えていただければ幸いです。
いろいろと定義に関しては下記のリンク先の右上の「search」に入力すれば定義のページに飛びます。
リンク:Code Saturne

void cs_user_initialization(cs_domain_t *domain) { cs_field_t *vel = cs_field_by_name("velocity"); cs_field_t *vel_m = cs_field_by_name("meanVel"); for (cs_lnum_t i = 0; i < cs_glob_mesh->n_cells; i++) { vel->val[i] = 1e5; } }

上記のコードの理解にお手伝いいただければと思います。
例えば

void cs_user_initialization(cs_domain_t *domain)

に関しては単に引数に構造体名「domain」のポインタを渡すという風に定義されていると考えるだけでよいですか?cs_user_initializationという関数は自分で定義したものではないです。これは場の初期化に使用するときに使う関数なのですが、引数で受け取ったポインタ値はそれより下のコード内で利用されていないと思うのですが、なぜそのようにポインタ値を引数で渡すようにしたのでしょうか。答えは結局人によるということになるのでしょうか。

また、

cs_field_t *vel = cs_field_by_name("velocity");

は「cs_field_by_name("velocity")」という関数みたいなもの?で「cs_field_t *vel」にポインタ値を格納しているだけだとは思いますが、正しいでしょうか?

cs_lnum_t i = 0; i < cs_glob_mesh->n_cells; i++

は「cs_lnum_t」型の変数「i」が、「cs_glob_mesh」という構造体の中の「n_cells」というメンバーの数以下になるまでiをつずつ増やしていくという理解で正しいでしょうか?「cs_glob_mesh->n_cells」とある場合は「cs_glob_mesh」は構造体、「n_cells」は構造体のメンバーという理解で正しいですか?

最後に

vel->val[i]

ですが、「vel」は構造体または配列で、その中のメンバーである「val」の「i」番目に右辺の値を格納しているということでしょうか。valを上記リンクで調べてみると「For each active location, pointer to matching values array」とあるのですが、結局「val」は「vel」という構造体の中の「val」という名前のメンバーでそれ自身は配列という理解で正しいでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

「i」が、「cs_glob_mesh」という構造体の中の「n_cells」というメンバーの数以下になるまでiを

「n_cells」というメンバーの数『未満の間』iを

です。

「val」は「vel」という構造体の中の「val」という名前のメンバーでそれ自身は配列という理解

cs_field.h によれば、 val はポインタです。

投稿2021/09/03 16:37

編集2021/09/03 17:09
jimbe

総合スコア13209

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tubasa1995

2021/09/03 17:16

やはりvalはポインタですよね。 ただ、ここではvel->val[i] = 1e5と書いており 実際には1e5という値でval[i]を書き換えているので実体のある数値ではないのかと思っていました。これがポインタというのがいまいち分からないです、 cs_field.hには*valの場合はポインタと書いてあり、valであれば実体のある数字なのかと思いました。
jimbe

2021/09/03 17:41 編集

ポインタは見た目は配列としても扱えます。 なお、「変数」と「数字」と「数値」は c ではしっかり使い分けないと相手に伝わりません。(特にプログラミング初心者やスクリプト系の方は数字数値は分かりにくいかもしれません。) val は(real とありましたので恐らく浮動小数点型の)ポインタで、n_cells 個分(以上)の大きさのメモリ領域を指しているものと思います。ですので val[i] のように配列として使っているのでしょう。 val はポインタ扱いでも配列扱いでも変数であって、「実態のある数字(数値)」という不可思議な表現のモノではありません。
Tubasa1995

2021/09/03 18:06

私がなぜポインタだと理解しにくいかというと このコードの意味は、速度場vel(velocity)を1e5という値に値に書き換えるために書かれたコードになります。ですので直接数値ではなくポインタ値(アドレス)で渡していたことがいまいち理解しがたかったことです。 このコードを流した後は実際に速度場は全体が1e5m/sという値になりました。つまりその速度場は流速という名のポインタ値を示しているということなのでしょうか。それともポインタそのものにメモリのアドレスでなく数値を持たせることは可能なのでしょうか?
jimbe

2021/09/03 19:06

私はこのライブラリが何をするものなのか知りませんので velocity フィールドが何なのかも知りません。 が、コメント頂いた言葉から拾いますと、速度場全体は n_cells が示す数分の値で表され、それを保持するために vel->val 変数が用意されているということになりますね。 c の配列は宣言時に大きさも定数で指定しなければならないため、必要に応じて拡大縮小することが出来ません。 そこで、配列と同じように使えるポインタを宣言し、必要な大きさが決まった時点でメモリを確保してそのアドレスを vel->val に設定することで、任意の大きさの配列として用いているものと思います。 なお、ポインタを配列として用いるということは、ポインタの変数に値(この場合は1e5)を入れることではありません。 配列とポインタの関係は、例えるなら「マンションそのもの」と「住所を書いた紙」の関係と似ています。 「マンションそのもの」に対して 101 号室に新聞を入れることを『マンション[101]=新聞』と書くとしますと、住所を書いた紙に 101 号室と付け加えても マンション[101] と同じ場所を示せますので、(現実なら誰か/何かがそこまで移動しなきゃならないという違いはありますが)『住所を書いた紙[101]=新聞』でも同じことになるのです。 ※あくまで例えですので、細かいツッコミは無しでお願いします。
Tubasa1995

2021/09/03 20:38 編集

いきなり個人的な用語を用いてしまい、すいません。 その通りで、空間をn_cells分だけ分割して、その一つ一つのセルに速度があります。その一つ一つのセルに対応する速度がvel->valに格納されていると思っています。 ですがvalがポインタということで戸惑いました。 つまり例えば簡潔に以下のようにすると for (i = 0; i < 10; i++) { vel->val[i] = 1e5; vel->val[0] = 1e5 vel->val[1] = 1e5 . . . vel->val[9] = 1e5 となってval[1]はポインタだけど変数のように表せるから valの中の[1]がアドレスのようなもので val[1]にしたら、そのアドレスの示す数値等 になるという理解で正しいでしょうか?
Tubasa1995

2021/09/03 20:44

配列とポインタの類似性 などで検索したらたくさんこれについて 書いてある記事を見つけました。 初めて知りました。本当に助かりました。
Tubasa1995

2021/09/03 20:51

ポインター=配列 としてポインターに配列を格納すれようの動作をすると 配列を渡すということはその配列の先頭のアドレスを渡すことと同じだから 結局のその先頭のアドレスとの相対位置が[i]で表されていることなんですね。 つまりvalはどこか別の場所で val=配列 のように定義されているということですね。
jimbe

2021/09/04 03:04 編集

> val[1]はポインタだけど変数のように表せるから val と val[1] は表すものが全く違います。 val はポインタ(cs_real_t*)ですが、val[1] はそのポインタの型の変数(cs_real_t)です。 ポインタなのは "val" と表記し [] を付けなかった場合です。 ポインタに関する記事の多さは、それだけ引っ掛かる方が多いという現れなのでしょうね。 「ポインタに配列を入れる(渡す)」と言う意味で書かれる "ポインタ=配列" という式ですが、これは 「配列を渡すということはその配列の先頭のアドレスを渡すことと同じ」 なのではなくその逆で、 「配列の名前だけを書いた場合([]が無い場合)は、配列の先頭アドレスを表す」という言語仕様なので、ポインタに配列の先頭アドレスを入れる(渡す)ことで配列を入れる(渡す)ことと同じになっています。 > 結局その先頭のアドレスとの相対位置が[i]で表されている その通りです。 > valはどこか別の場所で > val=配列 > のように定義されている イメージはそれで良いかと思いますが、もしその定義を探された場合を想定して(より混乱されるかもしれない)説明を追加させていただきます。 ポインタを使う理由は主に2つあります。 1つは、状況に応じて複数の変数(配列)の内の1つを使う場合です。 ある状況では変数 a を使い、別の状況では b 、さらに違う状況では c 、…という場合に if 分で判断して行うことも出来ますが、何度も判断が必要な場合には面倒です。 そこで、先に一度、使う変数(のアドレス)を選択してポインタに入れておくことで、以降は判断をしなくて済むようになります。 この場合には、ポインタ=変数 という式が出てきます。 もう1つは(先にも書きましたが)配列は大きさをプログラム作成時に決めておかなければならず、しかも決めた後は拡大縮小出来ません。 その為、メモリを必要に応じて確保してポインタに設定し配列として使う…ということがあります。(こちらのほうが多いかもしれません。) この場合、メモリの確保には malloc という感じの関数(正確にはシステムコール?)が使われるため、 ポインタ=malloc(~) という式になり、配列は出て来ません。
guest

0

単に引数に構造体名「domain」のポインタを渡すという風に定義されていると考えるだけでよいですか?

cs_domain_t型のポインタdomainを引数に持つ関数cs_user_initializationです。

引数で受け取ったポインタ値はそれより下のコード内で利用されていないと思うのですが、なぜそのようにポインタ値を引数で渡すようにしたのでしょうか。答えは結局人によるということになるのでしょうか。

書いた人に聞いてください。

Code Saturnecs_user_initializationをユーザー側で実装することを要求しているが、
その実装を書いた人はcs_user_initialization内でdomainを使わないことを選んだのでしょう。

cs_field_by_name("velocity")」という関数みたいなもの?

関数です。

「cs_field_t *vel」にポインタ値を格納しているだけだとは思いますが、正しいでしょうか?

少なくともポインタを返して代入はしています。
ただcs_field_by_name内でなにか副作用は起こしているかはわかりませんので、
ポインタ値を格納している「だけ」かどうかはわかりません。

は「cs_lnum_t」型の変数「i」が、「cs_glob_mesh」という構造体の中の「n_cells」というメンバーの数以下になるまでiをつずつ増やしていくという理解で正しいでしょうか?

はい

「cs_glob_mesh->n_cells」とある場合は「cs_glob_mesh」は構造体、「n_cells」は構造体のメンバーという理解で正しいですか?

->としてメンバにアクセスしているので、cs_glob_meshは構造体へのポインタです。

「vel」は構造体または配列で、

->としてメンバにアクセスしているので、構造体へのポインタです。

その中のメンバーである「val」の「i」番目に右辺の値を格納しているということでしょうか。

はい

valを上記リンクで調べてみると「For each active location, pointer to matching values array」とあるのですが、結局「val」は「vel」という構造体の中の「val」という名前のメンバーでそれ自身は配列という理解で正しいでしょうか。

はい

投稿2021/09/03 13:16

ozwk

総合スコア13553

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tubasa1995

2021/09/03 13:39

ご丁寧に回答していただきありがとうございます。 cs_glob_mesh->n_cellsに関して聞きたいのですが 「cs_glob_mesh」が構造体を示すポインタ値ということは分かりました。 「cs_glob_mesh->n_cells」とあるので「n_cells」は構造体のメンバだとは思うのですが、*(cs_glob_mesh->n_cells)しなくても具体的な数値まで「i」が増えていくのでしょうか?「i = 0; i < cs_glob_mesh->n_cells」とあるので少し混乱しているのですが 要するに (cs_glob_mesh->n_cells) *(cs_glob_mesh->n_cells) ではそれぞれ違う結果になると思うのですが 上側の(cs_glob_mesh->n_cells)でいいのでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問