C言語の課題がわかりません

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ウィーヤ

C言語の課題がわかりません

#1

投稿記事 by ウィーヤ » 17年前

プログラムを初めて学んで約2ヶ月しかたっていない学生の者です。
明日提出しなければならないC++の課題が、まったくわからなくて困っています。

課題内容は…
 高さh[m]の地点から速度u0(これはuに数字の0を下付けたやつです)[m/s]で質点を水平に投げたとき、質点が地上に到達するまでの時間T、および水平到達距離L[m]を算出するプログラムを作成せよ。ただし、0.1s毎の質点の位置x,yおよび速度成分u,vを画面に出力させること。またTおよいLは質点の位置が地面より下になった時点の値とし、厳密に求める必要はない。下記の関数は必ず作成すること。
・初期条件h、u0を入力する関数
・位置x,yを計算する関数
・速度成分u,vを計算する関数

以上、課題内容です。

今のところ、このプログラムはまったく進んでないです。
下2つの必要記入の関数は何となく理解できるのですが、1つ目の「初期条件h、u0を入力する関数」というものがよくわかりません。
数値演算関数内にprintfを書けということなのでしょうか。

最近、何とかポインタを理解できたという程度の知識しかもっていません。
どうぞよろしくお願いします。

管理人

Re:C言語の課題がわかりません

#2

投稿記事 by 管理人 » 17年前

ウィーヤさん、こんにちは。

3つの項目に上から番号を振りましょう。

1番はプログラムの問題ですが、2,3は単純に物理の問題ですね。
プログラムの書き方は、わかりますか?
物理的な式の解き方はわかりますか?

最初に出てくる物理の運動に関する3大公式を用いれば解けます。
最初にプログラムは関係なく、紙とペンでとけるかどうかが重要です。
紙とペンでとけなければ、プログラムがわかっても解けません。
一度問題を解いてみてください。

管理人

Re:C言語の課題がわかりません

#3

投稿記事 by 管理人 » 17年前

まず、1番はこのようにすればOKです。
必要な変数はここに宣言しました。
#include <stdio.h>

void main(){
	double l,u_0,T,L,x,y,u,v;
	printf("初速度 u_0(m/s) -> ") , scanf("%lf",&u_0);
	printf("高さ   h  (m)   -> ") , scanf("%lf",&h  );

}
以後キーボードから代入された値が(u_0,h)使えます。

管理人

Re:C言語の課題がわかりません

#4

投稿記事 by 管理人 » 17年前

後は、物理の公式に代入するだけです。
水平方向に投げたということは、速度のx成分は初速度に等しく、一定です。
初速度がそのままv_xとなります。
xの距離は素直に、速さ*時間になります。
y方向には最初力が加わっていないので、自由落下と同じになります。
速さのy成分v_yはgtとなります。
yの式から地上にぶつかる時のtが求まります。

この式を使えば解けます。
厳密に計算する必要はないということなので、
0.1秒ごとに増えていく値がこの値より大きくなった時点の値とすればよいわけです。
tを0.1ずつ増加させて計算しましょう。

ウィーヤ

Re:C言語の課題がわかりません

#5

投稿記事 by ウィーヤ » 17年前

ご回答有り難うございます。
今後、質問がわかりやすいように、かつ回答しやすいようにするために、項目に番号を振るようにします。


さて、項目1についてはわかりました。
しかし、理由がいまいちわからないです。
「関数として」というと、
#include <math.h>
は必要なのではないのでしょうか。
また
void main()
内に入れた場合は関数と言えないのでは?
上辺だけの知識しかありませんが、その教えていただけるとあり難いです。

また項目2・3の方ですが、物理の方は何ら問題はありません。
ペンと紙ですぐに解けます(^^
ただ、プログラムとして記入するのはちょっと自信がないですが…。

管理人

Re:C言語の課題がわかりません

#6

投稿記事 by 管理人 » 17年前

まず、これをコンパイルしてみてください。
実行してみて、自分のやりたいことがあってるか、確認してください。
#include <stdio.h>

#define g 9.80665

void input(double *v_0,double *h){
	printf("初速度 v_0(m/s) -> ") , scanf("%lf",v_0);
	printf("高さ   h  (m)   -> ") , scanf("%lf",h  );
}

void calc_xy(double *v_0,double *v_x,double *x,double *t,double *y){
	*x = (*v_x) * (*t);
	*y = 0.5f * g * (*t) * (*t);
}

void calc_v(double *v_y,double *t){
	*v_y= g * (*t);
}

void main(){
	double h,v_0,v_x,v_y,x,y=0,t=0;
	input(&v_0,&h);
	v_x=v_0;
	printf(" t\t   x\t   y\t   v_x\t   v_y\n");
	while(y<h){
		t+=0.1f;
		calc_xy(&v_0,&v_x,&x,&t,&y);
		printf("%4.1f\t%7.2f\t%7.2f\t",t,x,y);
		calc_v(&v_y,&t);
		printf("%7.2f\t%7.2f\n",v_x,v_y);
	}
	printf("T=%4.1f\tL=%7.2f\n",t,x);
}
よければ説明します。

管理人

Re:C言語の課題がわかりません

#7

投稿記事 by 管理人 » 17年前

まず、数値入力を実現したプログラムはこちらです。
#include <stdio.h>

void main(){
	double h,v_0;
	printf("初速度 v_0(m/s) -> ") , scanf("%lf",&v_0);
	printf("高さ   h  (m)   -> ") , scanf("%lf",&h  );
}
scanfの使い方さえわかれば、すんなりわかりますね。
scanfは変数をアドレスで指定している点に注意してください。

この入力部分を関数化するとこうなります。
#include <stdio.h>

void input(double *v_0,double *h){
	printf("初速度 v_0(m/s) -> ") , scanf("%lf",v_0);
	printf("高さ   h  (m)   -> ") , scanf("%lf",h  );
}

void main(){
	double h,v_0;
	input(&v_0,&h);
}
ポインタはわかるとおっしゃっていたので、説明する必要はないとは思いますが、mainからのinput呼び出しの際、アドレスを渡してやってinputでポインタとして受け取っています。
ポインタで渡された関数内では*をつけることで、main内と同じ変数として扱えますね。
ここでポイントなのは、scanf文の変数の前に&がなくなっていること。
ポインタで渡された変数は*をつければ、値をしめし、それをとればアドレスを示すことになります。

ここまでいいですか?

ウィーヤ

Re:C言語の課題がわかりません

#8

投稿記事 by ウィーヤ » 17年前

長々と説明していただき有り難うございます。
大丈夫です。何とかついていけてます。

管理人

Re:C言語の課題がわかりません

#9

投稿記事 by 管理人 » 17年前

では、具体的な部分へ。

input関数を作って、入力を受け付ける関数を作りました。

では、次は速さを計算する関数を作ってみましょう。

tが最初0の状態から0.1ずつ増やしていき、2秒になるまでループさせます。

while(t<2.0){
t+=0.1f;

ここの部分ですね。
速さのx成分はずっと変わらないので計算する必要はありません。
今回は用意しましたが、v_xという変数もわざわざ用意することも無いでしょう。

例によってポインタで計算するために、アドレスを渡してやります。
&v_y,&t
ここの部分ですね。

calcは計算する、vは速さという意味です。

速さを計算するcalc_vという関数に変数のアドレスを渡してやり、

v_y = g*t;

を計算します。紙とペンではすぐとけるということなので、物理的な解説ははぶきます。
これでy成分の速さが求まりました。

tは0.1ずつ増えていっているので、時間変化によって、v_yも計算されていきます。


ループを抜けた時、t=2の時の速さが求まっているはずです。

printfの出力を見てください。
#include <stdio.h>

#define g 9.80665

void input(double *v_0,double *h){
	printf("初速度 v_0(m/s) -> ") , scanf("%lf",v_0);
	printf("高さ   h  (m)   -> ") , scanf("%lf",h  );
}

void calc_v(double *v_y,double *t){
	*v_y= g * (*t);
}

void main(){
	double h,v_0,v_x,v_y,x,y=0,t=0;
	input(&v_0,&h);
	v_x=v_0;
	while(t<2.0){
		t+=0.1f;
		calc_v(&v_y,&t);
	}
	printf("v_x=%f v_y=%f\n",v_x,v_y);
}
次、最後の解説をします。

管理人

Re:C言語の課題がわかりません

#10

投稿記事 by 管理人 » 17年前

あ、今読み返してみると

>3つの項目に上から番号を振りましょう。

この文章は

「3つの項目に上から番号を振ります。」と最初かいていたのに、後から消した文章とつなげて変に「ふりなさいよ!」みたいな発言になってしまってますね^^;

自分が解説しやすいように、番号ふっただけなんで。
気にしてたらごめんなさい^^;

管理人

Re:C言語の課題がわかりません

#11

投稿記事 by 管理人 » 17年前

>ループを抜けた時、t=2の時の速さが求まっているはずです。

正確には1.9の時の計算結果が表示されますね。

ウィーヤ

Re:C言語の課題がわかりません

#12

投稿記事 by ウィーヤ » 17年前

ん?
while(t<2.0){
t+=0.1f;

この変数tの増やし方は初めて知りました。
数字の増減方法は
i++ やi--
しか知りませんでした。
この場合は(i++,i<20.0)として
t=0.1*i
と書けばよろしいのでしょうか。

管理人

Re:C言語の課題がわかりません

#13

投稿記事 by 管理人 » 17年前

次にx,yを計算する
calc_xy
という関数を作りましょう。

xとyの計算に必要な変数はなんでしょうか?
まず、当然x,yの計算結果を格納するためのx,yという変数が必要です。
その変数を受け取ります。
次に、
xは
x=v_x*t
で計算できますから、v_xとtが必要です。
これも、main関数から引っ張ってきましょう。

後重力加速度gですが、これは不変なので定義します。

#defineの使い方がわからなければ、また聞いてください。
ここでは「g」と書けば、9.80665という意味になると覚えておいてください。

それでは受け取るべき変数をうけとって、計算したものが
void calc_xy(double *v_x,double *x,double *t,double *y){
	*x = (*v_x) * (*t);
	*y = 0.5f * g * (*t) * (*t);
}
これです。
なんら難しくないですね?
掛け算の「*」なのか、変数のポインタを表す*なのか混合しそうなので、括弧をつけて明確にしました。

後はmain関数からよんでやればいいだけのことです。

ループの条件はy<hとし、設定したhよりyの方が大きくなれば終了です。
ループを抜けた時の値を表示してやれば、問いの解答となります。

ちなみに
printf("%4.1f  %7.2f  %7.2f  %7.2f  %7.2f  \n",t,x,y,v_x,v_y);
という表示の仕方は、数値をキレイにそろえて表示させる方法で、
%7.2fとかいたら、
「少なくとも7桁表示し、そのうち小数点以下は2桁表示で浮動小数点型」
という意味になります。
どの数値も7桁表示されるので、値がキレイにそろって表示できます。


これらを全て組み合わせるとこうなります。
#include <stdio.h>

#define g 9.80665

void input(double *v_0,double *h){
	printf("初速度 v_0(m/s) -> ") , scanf("%lf",v_0);
	printf("高さ   h  (m)   -> ") , scanf("%lf",h  );
}

void calc_xy(double *v_x,double *x,double *t,double *y){
	*x = (*v_x) * (*t);
	*y = 0.5f * g * (*t) * (*t);
}

void calc_v(double *v_y,double *t){
	*v_y= g * (*t);
}

void main(){
	double h,v_0,v_x,v_y,x,y=0,t=0;
	input(&v_0,&h);
	v_x=v_0;
	printf("  t\t  x\t   y\t   v_x\t    v_y\n");
	while(y<h){
		t+=0.1f;
		calc_xy(&v_x,&x,&t,&y);
		calc_v(&v_y,&t);
		printf("%4.1f  %7.2f  %7.2f  %7.2f  %7.2f  \n",t,x,y,v_x,v_y);
	}
	printf("T=%4.1f\tL=%7.2f\n",t,x);
}
若干むだがあったので、改良しました。

これでやりたいことあっていますか?

管理人

Re:C言語の課題がわかりません

#14

投稿記事 by 管理人 » 17年前

>この変数tの増やし方は初めて知りました。

i++

i = i+1;
と同じです。

一方

i=i+2;

i += 2;
と同じです。

i=i-3;

i -= 3;
と同じです。

i=i*0.2;

i *= 0.2;
と同じです。

これらはiを2回書かなくて済むので「若干」便利ですw

ウィーヤ

Re:C言語の課題がわかりません

#15

投稿記事 by ウィーヤ » 17年前

なるほど。
よくわかりました。しかし
t+=0.1f
の「f」、位置yの関数でも使用されてますが何なのでしょうか。

あと、実行してみたところ、自分のやりたいこととばっちり合っていました。

管理人

Re:C言語の課題がわかりません

#16

投稿記事 by 管理人 » 17年前

あ、floatのfです・・。
昔のくせでついつけてしまいました。
別に必要ありません^^;

管理人

Re:C言語の課題がわかりません

#17

投稿記事 by 管理人 » 17年前

最後尾にfを付けるとfloat型になり、
最後尾にdを付けるとdouble型、
lを付けるとlong double型に出来ます。
doubleからfloatにする意味は全くないので、省いてください。

こちらに省いたプログラム載せます。
#include <stdio.h>

#define g 9.80665

void input(double *v_0,double *h){
	printf("初速度 v_0(m/s) -> ") , scanf("%lf",v_0);
	printf("高さ   h  (m)   -> ") , scanf("%lf",h  );
}

void calc_xy(double *v_x,double *x,double *t,double *y){
	*x = (*v_x) * (*t);
	*y = 0.5 * g * (*t) * (*t);
}

void calc_v(double *v_y,double *t){
	*v_y= g * (*t);
}

void main(){
	double h,v_0,v_x,v_y,x,y=0,t=0;
	input(&v_0,&h);
	v_x=v_0;
	printf("  t\t  x\t   y\t   v_x\t    v_y\n");
	while(y<h){
		t+=0.1;
		calc_xy(&v_x,&x,&t,&y);
		calc_v(&v_y,&t);
		printf("%4.1f  %7.2f  %7.2f  %7.2f  %7.2f  \n",t,x,y,v_x,v_y);
	}
	printf("T=%4.1f\tL=%7.2f\n",t,x);
}

ウィーヤ

Re:C言語の課題がわかりません

#18

投稿記事 by ウィーヤ » 17年前

そうだったんですか…。

わかりました。
ちょっと頭がオーバーヒートしそうなので、
一息入れてから管理人さんの解説をみて、
なぜこうなるのかを考えながらやってみますね。

今のところ、管理人さんの解説を完璧に理解できている自信はないので、また質問することになると思います。
(たしか新しくトピックを作るんでしたね)

解決したわけではありませんが、とりあえずこのトピックは「解決」状態にしておきます。

長く書いていただき、有り難うございました。

管理人

Re:C言語の課題がわかりません

#19

投稿記事 by 管理人 » 17年前

プログラムは一見ゴミゴミして見えますが、
全く難しい処理はしていませんから、落ち着いてみてください。
最初から完成したプログラムをみるのではなく、私の解説にそってみていけば判ると思います。

少しでもわからない部分があれば、そのままにせずに必ず聞いて「完璧」にわかった状態にしてくださいね☆

閉鎖

“C言語何でも質問掲示板” へ戻る