🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

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

Q&A

2回答

5067閲覧

貸出時間の総計を算出するプログラム

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

0グッド

0クリップ

投稿2020/12/29 11:39

編集2020/12/29 12:23

C言語

1 2ある特定のボート(A,B,C...)の貸し出し時間の総計を算出するプログラムを作成したいと考えています。以下のようなデータファイルがあります。「標準入力」欄に入力したボートの名前に対して、「標準出力」欄にそのボートの貸し出し時間の総計が表示されるようにしたいと考えています。プロブラム実行時には「標準入力」欄にA,B,C...と入力します。 3「標準入力」A 4「標準出力」153 5となるように考えています。 6 7A O 09:00 8B O 09:05 9B I 09:30 10C O 09:31 11B O 09:45 12A I 10:03 13A O 10:20 14B I 10:38 15C I 10:55 16A I 11:10 17 18 19 20 21 22#include <stdio.h> 23 24#define LINESIZE 256 25 26int main(int argc, char *argv[]) { 27 FILE *fp; 28 char line[LINESIZE]; 29 char b, io; 30 int h, m, tm; 31 32 if ((fp = fopen(argv[1], "r")) == NULL) { 33 printf("Can't open the file.\n"); 34 return 1; 35 } 36 37 tm = 0; 38 for(; fgets(line, LINESIZE, fp)!=NULL;){ 39 sscanf(line, "%c %c %d:%d", &b, &io, &h, &m); 40 switch(io){ 41 case 'I': 42 tm += 60*h+m; 43 break; 44 case 'O': 45 tm -= 60*h+m; 46 break; 47 } 48 } 49 printf("%d:%02d\n", tm/60, tm%60); 50 51 fclose(fp); 52 53 return 0; 54}コード

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

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

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

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

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

y_waiwai

2020/12/29 11:40

しつもんはなんでしょうか。 質問文は編集できます。追記修正しよう
episteme

2020/12/29 12:41 編集

> ある特定のボート(A,B,C...)の貸し出し時間の総計を算出するプログラムを作成したいと考えています。 - ファイルに書かれた一行のデータはなにを意味しているのですか? - 呈示されたコードはなにをするものですか? - しつもんはなんですか?
退会済みユーザー

退会済みユーザー

2020/12/29 12:43

現状のコードは A O 09:00 B O 09:05 B I 09:30 C O 09:31 B O 09:45 A I 10:03 A O 10:20 B I 10:38 C I 10:55 A I 11:10 のA,B,Cのボート全体の1日の総計になっています。これをAのみの総計、Bのみの総計、Cのみの総計とそれぞれの総計を出したいと考えています。よろしくお願いいたします。
episteme

2020/12/29 12:52 編集

- 1つ目はボート名、3つ目は時刻ですね? 2つ目は? - 2つ目が O または I でなかったら? - 時刻が昇順に並んでいなかった場合は? ...などなど、あやふやな部分が多すぎます。 > ~と考えています。よろしくお願いいたします。 だから、なにをお願いしているのですか?
退会済みユーザー

退会済みユーザー

2020/12/29 13:10

説明がわかりずらくて申し訳ありません。 ・ボートは15隻所有している(A,B,C...) ・営業時間は09:00~18:00である ・ボート名、貸出/返却、時刻(10分単位) Oは貸出、Iは返却です。 今はこれらの情報から1日分の記録として、その日の貸し出し時間の総計を算出しています。これを利用して、A,B,Cそれぞれのボートの1日分の記録を出したいと考えています。
episteme

2020/12/29 13:16

しつもんはなんですか?
episteme

2020/12/29 13:22

貸出時間を収める箱(変数)をボート数分(配列で)用意し、 ボート名に応じて、どの変数に対して"時*60+分"を足すか/引くかを決めればいいでしょうね。
退会済みユーザー

退会済みユーザー

2020/12/29 13:23

どの部分を修正、もしくは加えれば、A,B,Cそれぞれの総計が出せるのかということです。今の状態は、すべてのボートの1日の集計になってしまっています。
episteme

2020/12/29 13:27

少なくとも現時点では貸出時間を積算する tm がひとつしかありません。 そこで int tm を int tm[15] とし、 ボートAなら tm[0], Bならtm[1] ... に対し "時*60+分"を足し/引きすればいい。
退会済みユーザー

退会済みユーザー

2020/12/29 13:35

tm = 0; for(; fgets(line, LINESIZE, fp)!=NULL;){ sscanf(line, "%c %c %d:%d", &b, &io, &h, &m); switch(io){ case 'I': tm += 60*h+m; break; case 'O': tm -= 60*h+m; break; } } この部分を15回おこなうのでしょうか。
episteme

2020/12/29 13:56

15回やればできるでしょう。が、もっと短く書けます。 for(; fgets(line, LINESIZE, fp)!=NULL;){ sscanf(line, "%c %c %d:%d", &b, &io, &h, &m); n = bが 'A'なら0, 'B'なら1, ... // **** switch(io){ case 'I': tm[n] += 60*h+m; break; case 'O': tm[n] -= 60*h+m; break; } } *** のところを何とかして実現するだけです。
退会済みユーザー

退会済みユーザー

2020/12/29 14:08

n = bが 'A'なら0, 'B'なら1, ... // **** こちらの部分の理解が出来ないのですが。n=bとはどのような意味なのでしょうか。
episteme

2020/12/29 14:14 編集

n = 「bが 'A'なら0, 'B'なら1, ...」 です。 b はファイルから読み込んだボート名ですよね。 それが 'A' なら tm[0]、'B'ならtm[1]... に対して計算すれば、 ボートAの総貸出時間はtm[0]に求まります。以下同文。
退会済みユーザー

退会済みユーザー

2020/12/29 14:29

if文ということでしょうか。
episteme

2020/12/29 14:32

あなた次第。ヒントはこれで充分では?
退会済みユーザー

退会済みユーザー

2020/12/29 14:36

なんとなくは理解できたのですが、解決できるかは不安です。ありがとうございました。
episteme

2020/12/29 14:42 編集

ボート名b は "ABCDEFGHIJKLMNO" の何番目にありますか(先頭を0番目として)? それがnです。 要は 「ボート名(char b) を通し番号(int n)に変換」するってことです。
episteme

2020/12/31 11:41 編集

えーと...テキトーに解決(close)しといて。それともまだできてない?
退会済みユーザー

退会済みユーザー

2020/12/31 12:05

まだ出来ていないのです。 諦め段階に入ってしまいました。
episteme

2020/12/31 12:07

コレ↓ができないの? > ボート名b は "ABCDEFGHIJKLMNO" の何番目にありますか(先頭を0番目として)? それがnです。 > 要は 「ボート名(char b) を通し番号(int n)に変換」するってことです。
BeatStar

2022/01/08 10:40

本気でこの問題に取り組むつもりなら『質問を編集』してください。回答者は基本的に質問本文を見て回答します。 少なくとも『OやIとは何か』とかのようなデータの並びに関しては質問本文では触れていません。
dodox86

2022/01/09 01:30

で、退会。
guest

回答2

0

質問文を素直に解釈すれば,

(1)
まず,ボートの名前を入力する処理が必要.
質問文に提示されているコードにはこれが無いから追加すればいい.

(2)
(1)の入力で指定されたボートについての集計をしたいのだから,
「ファイルから読み取ったデータがそのボート用のものであるときだけ」集計処理に使えばいい.

というだけの話に思える.


以下は,質問文に提示されているコードに,上記の(1),(2)を追加しただけのものだ.
これで,質問文で例示されている結果(A と入力すれば 1:53 という結果が表示される)が得られるが,これだと何か不足なのだろうか?

C

1#define LINESIZE 256 2 3int main(int argc, char *argv[]) { 4 FILE *fp; 5 char line[LINESIZE]; 6 char b, io; 7 int h, m, tm; 8 9 //↓(1)ボートの名前を入力するためのコードを追加↓ 10 char TgtBoatName; //ボートの名前用 11 12 printf( "Tgt Boat Name = ? " ); 13 TgtBoatName = getchar(); //入力処理 14 //↑(1)ボートの名前を入力するためのコードを追加↑ 15 16 if ((fp = fopen(argv[1], "r")) == NULL) { 17 printf("Can't open the file.\n"); 18 return 1; 19 } 20 21 tm = 0; 22 for (; fgets(line, LINESIZE, fp) != NULL;) { 23 sscanf(line, "%c %c %d:%d", &b, &io, &h, &m); 24 25 //(2)指定されたボートの記録だけを用いるように条件を追加 26 if( b == TgtBoatName ) 27 { 28 switch (io) { 29 case 'I': 30 tm += 60 * h + m; 31 break; 32 case 'O': 33 tm -= 60 * h + m; 34 break; 35 } 36 } 37 } 38 printf("%d:%02d\n", tm / 60, tm % 60); 39 40 fclose(fp); 41 42 return 0; 43}

投稿2021/07/06 04:47

fana

総合スコア11985

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

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

rubato6809

2021/07/06 10:16

なるほど今わかりました。確かに質問文には 「標準入力」A 「標準出力」1:53 とありますものね。2日ほど前に新たに出した質問で「~条件を追加したい」とは if( b == TgtBoatName ) である可能性が高い・・・とはいえ、質問者の文章はあいまいだと思います。
fana

2021/07/06 11:19

まぁ,別に, 「とりあえず全部求めて配列に保持しておき,指定されたやつだけを出力する」的な形だろうが 実際上どうでもいい程度の差ではあると思うのですが… この内容で質問している側の立場からすれば,「配列」とかいう要素が登場するだけで「その分だけ難易度が上がる」ことになるのかもしれないので, 「配列」無しで言われたことだけするバージョンも欲しいかな,と.
AOmi3

2022/01/08 09:29

すいません、標準入力にAを入れて、1:53と出力するのにはどうしたらいいのでしょうか? お手数をおかけしますが、よろしくお願いいたします。
jimbe

2022/01/08 10:07 編集

私は試していませんが、こちらのコードで出るのではないでしょうか。 どうしたらと言われても、何がどうなって"どうしたら"なのか分からないと思います。
dodox86

2022/01/08 10:09

なぜ今頃。(質問投稿から1年、最後のコメントからも半年経過)
thkana

2022/01/08 11:23

このボート貸出を定番の課題にしている教員がいるみたいですよ。過去数年間でぼちぼちとその質問を見かけます。つまり学生の方は代がわりしている、と。少しずつ条件が変わっていたりして、出題する方も苦労しているんだなぁ、と思います。
jimbe

2022/01/08 12:30

どこかの企業の方か、新人用の研修ネタを教えてくださいという質問もありましたね。
AOmi3

2022/01/09 00:00

みなさまできました。ありがとうございました(。-_-。)ポッ
jimbe

2022/01/09 04:31

teratail としては課題のカンニングデータベースになることは本望では無いでしょうけど…。
guest

0

半年も諦めなかったことに驚くともに、その粘り強さに敬意を表して、こちらにしゃしゃり出てきました。

次の部分は、他の回答者も指摘されているように、貸出時間を積算する変数 tm がひとつしかありません。b の値('A', 'B', 'C' など)を無視しています。

C

1 tm = 0; 2 for(; fgets(line, LINESIZE, fp)!=NULL;){ 3 sscanf(line, "%c %c %d:%d", &b, &io, &h, &m); 4 switch(io){ 5 case 'I': tm += 60*h+m; break; 6 case 'O': tm -= 60*h+m; break; 7 } 8 }

Aの積算時間、Bの積算時間、Cの積算時間・・・を tm ひとつで扱うことはできません。
では、変数を tm_A, tm_B, tm_C ... としますか?後々たいへんな事になりますので、これはお勧めできません。
積算時間を配列にするのです。

ボートAなら tm[0], Bならtm[1] ... に対し "時*60+分"を足し/引きすればいい

  • Aの積算時間は tm[0] で
  • Bの積算時間は tm[1] で
  • Cの積算時間は tm[2] で

計算処理し保持する、ということです。
なお、コードを簡単にするため、ここではボートを A, B, Cの三艘だけにします。後でボートの数を増やすのは簡単ですから。

配列にするので、int tm; の代りに
int tm[3] = {0}; としましょう。これだけで tm[0] ~ tm[2] が全て 0 に初期化されます。元のコードでは tm = 0; という行で積算時間を0にしていることに対応します。

C

1 while (fgets(line, LINESIZE, fp) != NULL) { 2 sscanf(line, "%c %c %d:%d", &b, &io, &h, &m); 3 4 switch (io) { 5 case 'I': 6 switch (b) { 7 case 'A': tm[0] += 60 * h + m; break; // "A I .. "を処理 8 case 'B': tm[1] += 60 * h + m; break; // "B I .. "を処理 9 case 'C': tm[2] += 60 * h + m; break; // "C I .. "を処理 10 } 11 break; 12 case 'O': 13 switch (b) { 14 case 'A': tm[0] -= 60 * h + m; break; // "A O .. "を処理 15 case 'B': tm[1] -= 60 * h + m; break; // "B O .. "を処理 16 case 'C': tm[2] -= 60 * h + m; break; // "C O .. "を処理 17 } 18 break; 19 } 20 }

で計算できます。ここで

n = 「bが 'A'なら0, 'B'なら1, ...」

  • b == 'A' なら n = 0 に
  • b == 'B' なら n = 1 に
  • b == 'C' なら n = 2 に

すればよいのです。上記コードは次のように整理できます。

C

1 while (fgets(line, LINESIZE, fp) != NULL) { 2 sscanf(line, "%c %c %d:%d", &b, &io, &h, &m); 3 int n = 「bが 'A'なら0, 'B'なら1, … にする」 ; 4 5 switch (io){ 6 case 'I': tm[n] += 60 * h + m; break; 7 case 'O': tm[n] -= 60 * h + m; break; 8 } 9 }

配列を使えば、行数を減らすことができ、見通しが良くなったと思いませんか。ボート毎の変数を添え字変数 n で特定できるtm[n])からです。


次に「bが 'A'なら0, 'B'なら1, … にする」 所をどうするか。そこに注目します。

  • もちろん if ~ else if ~ else if でもできます。

C

1 if (b == 'A') n = 0; 2 else if (b == 'B') n = 1; 3 else if (b == 'C') n = 1;
  • これは switch ~ case で書いてもよい。
switch (b) { case 'A': n = 0; break; case 'B': n = 1; break; case 'C': n = 2; break; }
  • ボート名 b は(先頭を0番目として)"ABCDEFGHIJKLMNO" の何番目にあるか?

こういうことかもしれません。例えば、boat2num() という変換関数を作っておき、

C

1int boat2num(char b) 2{ 3 int n; 4 char *bName = "ABCDEFGHIJKLMNO"; 5 for (n = 0; bName[n] != '\0'; n++) { // 先頭から見て行って 6 if (bName[n] == b) // b と一致したら 7 return n; // その n を返す 8 } 9 return (-1); // 見つからなかったら? 10} 11 12 // 途中省略 13 sscanf(line, "%c %c %d:%d", &b, &io, &h, &m); 14 int n = boat2num(b); /// A,B,C => 0,1,2 に変換する 15 switch (io) { 16 case 'I': tm[n] += ...
  • ところで 'A', 'B', 'C' はアスキーコードです。その値は 'A' = 0x41 = 65, 'B' = 0x42 = 66, 'C' = 0x43 = 67 ... と連続した値ですから、

C

1 int n = b - 'A';

この一行だけで十分なのです。検算してみます。

  • b == 'A' なら 'A' - 'A' → 0 (即ち n = 0; と同じ)
  • b == 'B' なら 'B' - 'A' → 1 (即ち n = 1; と同じ)
  • b == 'C' なら 'C' - 'A' → 2 (即ち n = 2; と同じ)

・・・という具合いで、わかってしまえば、「ボート名(char b) を通し番号(int n)に変換」するやり方はいくつもある(他にもやり方はあるでしょう)ので、どうするかはあなた次第です。


最後に、それぞれのボートの積算時間を表示する、とはループを使って、ひとつずつ表示するということです。例えば

C

1 for (n = 0; n < 3; n++) { 2 printf("%c: %d:%02d\n", 3 n + 'A', tm[n] / 60, tm[n] % 60); 4 }

最後の最後に、積算時間の合計を表示するなら tm[0] ~ tm[?] を合計して、
表示すればよい。それは質問者にお任せします。

投稿2021/07/05 05:21

編集2021/07/05 05:34
rubato6809

総合スコア1382

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

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

退会済みユーザー

退会済みユーザー

2021/07/05 05:48

丁寧に解説いたたきありがとうございます。時間をかけて読ませていただきます。
fana

2021/07/06 04:24

そもそものやりたいことというのは > ある特定のボート(A,B,C...)の貸し出し時間の総計を算出する > 「標準入力」欄に入力したボートの名前に対して、「標準出力」欄にそのボートの貸し出し時間の総計が表示される という話なのでは…? この内容に対して,「tmが1個しかないから配列にせよ」という話になる意味がまるでわからない.
fana

2021/07/06 04:30

ああ,「質問への追記・修正、ベストアンサー選択の依頼」の中で 質問者が > A,B,Cそれぞれのボートの1日分の記録を出したいと考えています と書いたのを,「全てのボートに関する記録を同時に」と解釈されて話が進んでいるのですね. (各ボートの記録を求めたいというのはプログラムを使う人のやりたいことでしかなく,プログラムが受け持つ仕事は,「特定の」ボートの記録を求めること であるように見えるが…?)
rubato6809

2021/07/06 10:24

fanaさん 「全てのボートに関する記録を同時に」と解釈されて話が進んでいる・・・その通りです。なので配列を設けなさい、としました。 こうなれば、コード例をいくつか見てもらって少しでも発想のタネにしてもらう効果はあるだろう、ということで。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問