- ベストアンサー
C言語でのプログラム作成順序とデータの個数表示方法
- C言語でプログラムを作成する順序についてアドバイスをお願いします。
- 時間データを読み込み、30分ごとのデータの個数を表示するプログラムを作成したいです。
- データの範囲が24を超える場合にどう処理すれば良いか、また個数を数える関数の有無について教えてください。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
回答のNo.1+No.3の考え方で細かく書きますと以下のようになります。 1.時間データファイルのオープン等を行う 2.個数を保持するカウンター配列をゼロで初期化 例:int counter[48]; の counter[0]からcounter[47]にゼロを代入 ※Cの配列は添字が0から始まるので counter[0]からcounter[47]としました 0:00 ≦ 時刻 < 0:30 → 添字0 0:30 ≦ 時刻 < 1:00 → 添字1 : : 23:00 ≦ 時刻 < 23:40 → 添字46 23:30 ≦ 時刻 → 添字47 と対応づけるように考えています 3.時間データファイルから1件ずつ読み込むループ ※ループの終了条件は、時間データファイル中のデータを最後まで読んで残りのデータが無いこと 注意:項3.1~3.4はループ中の処理です 3.1 "時" と "分" を分離 ※時刻("時分")が浮動小数点型であれば、整数部を "時"、小数点以下を "分"として分離 例:1.382500 → 整数部 1を変数hour、小数点以下 0.382500 を 変数minute に代入 3.2 "時" を2倍した値をカウンター配列の添字に代入 例:soeji = hour * 2 3.3 "分" が0.5以上(30分以上)であれば、カウンター配列の添字に1を加える 例:soeji++ あるいは soeji = soeji + 1 13時30分から13時59分であれば、項3.2と項3.3により 13 × 2 + 1 → 添字は 27 3.4 時刻に対応するカウンター配列に1を加える 例:counter[soeji]++ あるいは counter[soeji] = counter[soeji] + 1 13時30分から13時59分であれば、counter[27] に 1を加えます 4.時刻ごとに個数(=カウンター配列の内容)を表示する ※好き好きですが、表示のためのループを作るのであれば、"時"が同じものをまとめて表示する方がロジックを書きやすいと思います 0:00 ≦ 時刻 < 0:30 → 添字0・・・ counter[0] 0:30 ≦ 時刻 < 1:00 → 添字1・・・ counter[1] ------------------------------------------------------ 1:00 ≦ 時刻 < 1:30 → 添字2・・・ counter[2] 1:30 ≦ 時刻 < 2:00 → 添字3・・・ counter[3] ------------------------------------------------------ の区切りかたでループ中で2つずつ表示する。 ※説明がわかりにくかったら、すみません 5.時間データファイルのクローズ等を行う
その他の回答 (5)
- neko1963
- ベストアンサー率49% (127/258)
NO.5の補足です。 「時間データ中に日付が無く、なおかつ日付が連続している」のであれば、時間データの「時」が23から0に変わったタイミングで日付の添字に1を加えることになります。 例えば366日分の2次元配列 counter[0][0]~counter[366][48]を使った場合 例: 0.012500 → counter[0][0] に1を加える・・・1日目の始まり 0.499167 → counter[0][0] に1を加える : : 23.118333 → counter[0][46] に1を加える 23.403611 → counter[0][46] に1を加える 0.455278 → counter[1][0] に1を加える・・・2日目の始まり 1.665833 → counter[1][3] に1を加える : : を行うロジックで実現できると思います。 ※時間データの「時」が 23から0に変わった時に日付の添字に1を加えれば実現できますね。
- neko1963
- ベストアンサー率49% (127/258)
>当然「ある日の0時から0.5時のデータ」と「10日後の0時から0.5時までのデータ」は違う箱に格納されます。 「時・分」だけで無く、日付でも分けてカウントするということですね。 御質問にあった時間データが「時・分」だったので、時・分と解釈していました。 日付でも分けてカウントする場合はカウントした結果を入れる箱(配列)の数が多くなりますが、考え方は大差ないと思います。 一度に処理するデータの日付の範囲は限定できるのでしょうか? 例えばデータの日付が1か月分(10/1から10/31とかに限定できるか) 2次元配列を使うというのも1つの方法として考えられます。 格納先の添字を算出する際に日付を考慮するだけで済みます。 例:2次元配列 counter[31][48] とすれば、0.5時間ごとに31日分まで格納できます。 1次元配列 counter[1488] でも0.5時間ごとに31日分まで格納できますが、2次元配列の方がわかりやすいでしょうか。 1年分にしたければ、2次元配列を使えば counter[366][48]とすれば格納できます。 ※この場合、日付→添字、添字→日付に変換するロジックが必要ですが 集計できる日付の範囲を何日分・何ヶ月分・何年分と限定したくないようであれば、counter[1000][31][48]とすれば、1000ヶ月×31日分かつ0.5時間単位の箱(配列)となりますね。
補足
ありがとうございます。 返事が遅くなって申し訳ありませんでした。 助言を参考にチャレンジしてるのですがなかなかうまくいかなくて。。。。 配列の知識不足です。。。
- neko1963
- ベストアンサー率49% (127/258)
回答No.1の補足です。 細かいことを書くと、御質問の文章中の |1、時間が書いてあるデータを読み込む | 読み込むデータは時間で24時間を越えると次の日の0時から始まります。 | 0~24の数字がループしているデータです は、”0~23の数字がループしているデータ” では無いでしょうか? 時間というか、24時制の時刻だと思いますが、0時と24時の両方があるのはおかしいと思いますので。 試しに回答No.1の考え方で Cのプログラムを作ってみましたが、考え方自体は問題無さそうです。
補足
>>”0~23の数字がループしているデータ” では無いでしょうか? わかりにくくてすいません。 おっしゃるとおりです。 0時と24時があるのはおかしいですね。 私の書き方が適切ではありませんでした。
- YKKIKS63
- ベストアンサー率44% (22/50)
多少なりとも、プライベートおよび業務でC言語等でプログラムを作ったことがある者です。 No.1の回答者の方も書いておられますが、気になるのは、データ例として示された小数です。例示のような小数で正しいのであれば、その小数の意味を理解できておられますか?それが分かっていないのであれば、まずは、この課題の出題者がいるのであれば質問して理解してください。 データの意味が理解できている、もしくはできたことを前提に以下、私の経験に基づく一般的な話を記します。 プログラムとは別にむずかしいものではありません。もちろん複雑な処理を行うものは、それ相応にプログラムに時間や経験が必要になったり、例えば「連立方程式をプログラムで解く」というようなものは(20年以上前の記憶でうろ覚えですが、ルンゲ・クッタ法だったかな?)とかの"アルゴリズム"の理解が必要になったりします。これは、「日本語の文章を書く」のと同じです。複雑で高度な言い回しや慣用句を駆使したりする文章もあれば、「これはラジオです」みたいな単純な文章もある、一方で、たった17文字しかないけど自分で作るのは知識、経験、語彙の豊富さ、その中からどの語彙を選ぶのかの感性が必要となる俳句等々。プログラムも同じですが、基本となる部分は簡単です。例えばご質問の問題のように。 ポイントは、自分の目と手でプログラムにさせたい処理を行う場合どうするかを、文字で整理できるか否かです。文字として整理できないのであれば、プログラム以前の問題です。与えられるデータが小数で正しいのであればその意味を理解できているか否かも同様です。 やりたいことを文字で整理できたとしたら、あとはそれを使いたいプログラム言語の構文や関数を用いてプログラムに置き換えていくだけ。 例えば、 データがなくなるまで以下を繰り返す。 i番目のデータはどの時間帯に属するデータ? 属する時間帯毎の個数カウンターを+1する。 ものすごく大雑把に書けば以上のとおり。 C言語の経験が浅い初心者には、「繰り返すってどうすればいいの?」等、やりたいことを日本語で整理できても、それをC言語でどう表現するのかが分からないことは多々あるでしょう。 そのような場合は、C言語の本を見る、経験者に教えてもらう等してください。経験者に教えてもらったら、少なくとも、教えてもらったC言語のキーワード("配列"とか"条件分岐"とか"for文"とか"if文"とか)については、自分でC言語の本を見たり、簡単な処理をプログラムしてみる等、理解を深めてください。 経験者に答えのプログラムコードを教えてもらったらそれで満足、というのであれば、以降は無視してください。読むだけ無駄ですから。 この問題をコード化する際のヒントを以下に示します。 "繰り返す" → for文、while文等々 ※データ個数が確定(例えば常に100個等)であるなら、for文が分かりやすいかな。 データ個数が不定、未定の場合、No.1回答者様の書かれた 「読み込むデータが無くなるまで」・・・(◎) という条件で繰り返し処理を行うことになります。この場合は、while文を使うことに なり、その場合、一般的に◎のような判定を行います。 このあたりは、C言語の入門本のwhile文の項に説明が載っていると思います。 "どの時間帯に属する" → 時間帯を示す、その時間帯の初めの時刻、終わりの時刻との大小比較 ※注意事項としては、時間帯と時間帯の境目の時刻を示すデータはどの時間帯 に属するのかには要注意。例えば"1:30"を意味するデータ値は、1:00~1:30所属? それとも、1:30~2:00所属?これにより、大小比較の際に、">"や"<"なの か">="や"<="なのかが変わってきます。 で、どこに属するのかを"判定"して、属する時間帯用のカウンターを更新するためには、 更新すべきカウンターを選択する条件分岐が必要になるのはわかりますよね? 条件分岐のポピュラーなのはif~else文です。 しかしここでは、「24時間を30分刻みの時間帯に分けてカウント」の選択が必要。40個以上 のカウンターの中から必要なひとつを選択するための条件分岐です。if文でやってできないこ とはありませんが、C言語にはselect文があります。こちらを使う方が分かりやすいでしょう。 しかし、それでも単純に言って48個もcase文を書くのはつらい... とうことで、No.1の回答者のご回答のように、時間帯ごとのカウンターを"配列"でもつように すると....一番目のカウンターは0:00~0:30に属するデータの個数、二番目のカウンター は、0:30~1:00に属するデータの個数...が入る。ということ、例えば3:45を示すデータは何 番目のカウンターでカウントすればよいのかを計算で求めることができるはず。 counter[0]:0:00~0:30→0.0~0.5のデータなら、これでカウント counter[1]:0:30~1:00→0.5~1.0のデータなら、これでカウント ・・・ ●"No.1の回答者様の言う「添字」ってわかりますか? 上で示す、[ ]の中の数字のことです。ちなみにC言語の配列では添字は0からであっ たと記憶しています。間違っていたら済みません。 なお、"配列"はC言語では避けて通れない、しかし理解すると便利なものです。 現時点で理解できていなくてもかまいません。頑張って理解を深めてください。 「"配列"なんかわからない」のは初心者にとって恥ずかしいことではありません。 初心者教育をする立場であった経験から言いますと、超初心者向けテキストを 作る際には、かならず説明にページを割いてきました。すなわち、初心者にとって 特に、プログラム自体の初心者にとって、つまずきやすく、挫折の原因になるもの だからです。 コード例を示すと簡単なのですが、それではせっかくの質問者様の経験蓄積のチャンスを奪うことになるので、以上、文章でヒント的なことを示しました。 ちなみに、C言語には、1関数で、「ある範囲のデータをカウントする」機能をもつものはありません。 ただし、C言語といっても、ISO標準(世界標準)の仕様に基づくものから、ソフト会社が独自の機能を持たせて世に送り出しているC言語(正しくはC言語でかかれたプログラムをPCとかの上で実行できるようする"コンパイラ")もあります。こちらの方には、あなたの質問にある処理を1関数で実現できる関数が提供されているかもしれません。 しかし、もしも、あなたが、何らかの目的(仕事で使うとか、プログラム会社への就職を目指しているとか)をもってC言語を勉強しようとしている方なら、あくまでも、標準のC言語を勉強していくことを強く勧めします。 ※標準のC言語:昔は"ANSI C"とか言ってましたが今は???「ISO C」とか「標準C」とか言っているのかな それにしても、質問の問題(課題?)を見ていると、質問者の方の立場(大学生、中学生、社会人とか)はなんなんだろう?初心者向けの課題だとしたら...(最後の文は独り言です)
補足
長文ありがとうございます。 >>データ例として示された小数です。例示のような小数で正しいのであれば、その小数の意味を理解できておられますか? これは私が勝手に決めました。 今回は「時間」にしていますが「分」、「秒」のどれかに統一できればいいと考えています。 プロットする際に一番見やすいのではないかと考えたからです。 >>それにしても、質問の問題(課題?)を見ていると、質問者の方の立場(大学生、中学生、社会人とか)はなんなんだろう?初心者向けの課題だとしたら...(最後の文は独り言です) 私は大学生です。 授業の課題ではありません。研究の解析をする際にこのようなプログラムがあれば便利だと考えて作ってみようと考えました。C言語は授業で習いましたがまだまだ初心者です。 >>"繰り返す" → for文、while文等々 データの数が1万個以上あるのでwhile文を使ってます。 >>C言語にはselect文があります。 知らなかったので参考にしてみます。 >>●"No.1の回答者様の言う「添字」ってわかりますか? わかりませんでした。 私はまだ配列をあまり理解できていません。勉強しなおしてみます。
- neko1963
- ベストアンサー率49% (127/258)
時間データの表現形式が良くわかりませんでしたが、 例えば 0.012500 というのは 0時間7分30秒 と解釈してよろしいでしょうか? ■順序(例) データの個数を持たせる変数は配列にします。 順序は 1.時間が書いてあるデータを読み込む 2.時間の "時"と"分" から、配列の添字を算出する ・ "時"の数字 ・ "分"が 0.5より小さいか、あるいは0.5以上か? 3.項2で算出した添字で示される配列要素に1を加える ※以下、項1で読み込むデータが無くなるまで、項1~3を繰り返す ■範囲のデータの個数を数える関数 単純に、データの個数を保持する配列に1をプラスするのを繰り返せば良いので、特に関数は必要ないと思いますが。
補足
>>時間データの表現形式が良くわかりませんでしたが、 例えば 0.012500 というのは 0時間7分30秒 と解釈してよろしいでしょうか? わかりにくくてすいません。 その解釈の仕方で合っています。
補足
わかりにくくて申し訳ありません。 私の頭も混乱していました。 書き方が悪くて誤解が生じているようです。 私がつくりたいプログラムはcounter[48]ではないのです。 読み込んだデータを参照して0から23,99999時のどこかの配列を+1するのではなく、 感覚としてはデータを30分毎に区切ってそのデータを数えていくものです。 ですので、当然「ある日の0時から0.5時のデータ」と「10日後の0時から0.5時までのデータ」は違う箱に格納されます。それがループするわけなのでcounter[]の箱の数もデータの数が多ければ多いほど増えていくことになります。 ややこしくて申し訳ありませんでした。