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

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

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

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

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Q&A

解決済

4回答

2088閲覧

標準入力で複数整数を入力して、出力1行目に最大値、2行目に最小値を表示させたい。 「C言語」

ryuuabis

総合スコア24

C

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

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

0グッド

1クリップ

投稿2021/10/27 00:05

前提・実現したいこと

C言語で、標準入力で複数の整数を入力して、出力1行目に最大値、2行目に最小値を表示させるプログラムを作っているのですが、最小値がなぜか0になってしまいます。
最小値単体で、プログラムを書くとうまく最小値が表示されるのですが、最大値と組み合わせるとうまく表示されません。
なぜなのでしょうか。。
すみませんが、ご教授お願いいたします。

発生している問題・エラーメッセージ

入力 19 5 40 25 出力 40 0

該当のソースコード

#include <stdio.h> int main(void) { int data, max, min; scanf("%d", &max); for (; scanf("%d", &data)==1;){ if (data > max) max = data; } for (; scanf("%d", &data)==1;){ if (data < min) min = data; } printf("%d\n",max); printf("%d\n",min); return 0; }

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

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

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

episteme

2021/10/27 00:37

> 最大値と組み合わせるとうまく表示されません。 「うまく表示されません」を説明してください。なにが/どのようにうまくないんですか?
ryuuabis

2021/10/27 01:03

>出力1行目に最大値、2行目に最小値を表示させるプログラムを作っているのですが、最小値がなぜか0になってしまいます。 例で言うと、最大値の40は表示されるが、最小値の5が表示されず0になるという意味です。
fana

2021/10/27 01:34

0になるのは「たまたま」だと思うが, 0になるのなぜか? とかいうよりも以前に, 初期値不明な min が最初に用いられる場面が別の値との大小比較っていう状態について何も思わないのだろうか?
guest

回答4

0

なぜなのでしょうか

やることの筋道がしっかりと立てられていないから,ではないでしょうか.

コードを書き始めるよりも前に「何をどういう順序で実施していけば所望の動作を達成できるのか?」という事柄を確定させる:
例えば,以下のような手順をとれば良かろう,みたいな方針をしっかりと考えてみることです.

1. 初期化 : 「現在までの最小値」と「現在までの最大値」という変数を用意し,適切に初期値を与えておく. 2. メインの処理 : 【整数を1つ入力させ,その入力値に基づき「現在までの最小値」と「現在までの最大値」を更新する】という処理を複数回繰り返す. 3. 結果の表示 : 「現在までの最小値」と「現在までの最大値」を表示する.

この処理の大枠だけではまだ下記のような未定事項があるので実装できません.

  • 「適切な初期値」ってのは具体的には何だよ?
  • 「複数回の繰り返し」を抜ける方法は何か?
  • 「複数回繰り返す」部分が1回も実施されない場合はあり得るのか? あり得るならば,何かそのケースへの対応が必要であろうか?

……といった事柄に全て決着をつけたら,あとはそのとおりに実装します.

投稿2021/10/27 01:23

編集2021/10/27 08:01
fana

総合スコア11996

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

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

fana

2021/10/27 01:26

このような手順をしっかりと考えれば, 「整数を4個入力するケースでは scanf を何回実施することになるのか?」みたいなことは自明となりますし, scanf を伴うループを複数個所書いちゃったりすることはなくなるでしょう.
fana

2021/10/27 01:28

実装してみた結果が所望の動作をせず,デバッグしてみても理由がわからん,という状況でこのような場所で質問するのであれば, コードだけではなく,そのコードの基となった「何をどういう順序で実施すればいけると考えたのか」という話を明記していただきたい.
fana

2021/10/27 01:46

低評価理由をご教示願いたく. 私としては 想定される根本的な原因 を述べたつもりであるが, 「そういうのはいいから」みたいな話であれば,そうだと明言していただきたい.
K_3578

2021/10/27 07:55

>低評価 低評価した本人には回答を編集した場合に通知が行くのでそういう理由で編集を一度行ったらいいかと この手の無言低評価は大体理由書いてくれませんが...
fana

2021/10/27 08:04

(編集内容が特段無いのに編集するのって避けたいところですが) せっかくご教示いただいたので,やってみました. #自身で無言低評価をしたことないので,通知が行かないというのは盲点でした.
K_3578

2021/10/27 08:09

>通知が行かない 回答の編集ページの下部に赤字でそんな感じの旨が書いてあったと思います。 低評価をするという事は回答を誤っている回答であると判断した訳なので回答が修正されて 正しい回答になれば外してもらいたいという運営の思惑があるのかと推測してます
fana

2021/10/27 08:25 編集

低評価を入れた回答が編集されたときだけでなく 低評価を入れた回答にコメントが付いた場合にも通知が行くものだと思っていた,ということです. このへん,微妙に一貫性がない(?)ですね. ・質問への 追記・修正依頼 に何か書いた場合 ・回答へのコメント を書いた場合 ・回答への評価 をした場合(コメント無しで) ・(他にもあるかな?) で,通知が出る条件がちょっとずつ違うっていう(いまだに把握できていない)
K_3578

2021/10/27 08:37 編集

>低評価を入れた回答にコメントが付いた場合にも通知が行くものだと思っていた,ということです. あぁ成程。 意図を読み違えたようで申し訳ない。確か以前に他のユーザーの方に教えて頂いて自分も把握したのでこれについてはどこかに載っているかわからないですね。 追記・修正依頼は既にコメントしていた場合は質問者のコメント、質問文の修正で通知が来て、 低評価をしていた場合は「評価を下げた質問が修正されました」というような通知が来たはずです。 回答へのコメントは他ユーザーのコメント、回答の編集が通知される 回答への評価は低評価した場合のみ編集が「あなたが評価を下げた回答が編集されました」と通知される という条件だと私は思ってますが、一度運営に問い合わせてみてもいいかもしれませんね。 特に質問の編集に関しては一切通知が来なかった事が何度かあったので
guest

0

まず、前提そのものが違います。
プログラミングっていうのは、『こう書けばいい』というものではありません。
それとつぎはぎをして行うものでもありません。

プログラミングとは『現実世界のシミュレーション』であり、「ロジック(= 論理)を考える」ことです。

とりあず、C言語ではどう書くかとかは置いといて、「現実世界でならどうするか」を考えてみましょう。
たとえば、

[依頼] ある人(Aさん)が数字を一個ずつ言います。その人が言い終わったら、その中から最大値と最小値をそれぞれ私に言ってください。

というような依頼かなんかだと考えてみてください。
質問者さんならどうしますか?

普通に考えると、

[Flow1] 1. Aさんが言い終わるまで聞く (それとメモを取る) 2. (1)で言われた数字の中から最大値と最小値を考える

のような流れになるはずです。

では最大値とはなんでしょうか。最小値とはなんでしょうか。

最大値: (対象データ群の中で)一番大きい値
最小値: (対象データ群の中で)一番小さい値

ですね。

では、この二つは排他的(?)でしょうか。つまり、同時に計算できないのでしょうか?

たとえば平均とかのような場合はきついですね。
平均の計算は
平均 = 合計値 ÷ 個数
だったはずです。(場合によって言い方が変わるが)
この合計値と平均値は同時には計算できませんね。

でも最大値と最小値は計算できるはずです。

仮に別々で計算するとしても、大体、上のFlow1でできるはずです。

次に、ご自分のコードを読んでみましょう。
コードは出鱈目に書くものではありません。

私たちが上のやり方(Flow1)でやるようなことをfor文だの変数だので表現しているだけです。

コードを読むコツは『一行レベルで、その行が何をしているかを考えながら読む』です。

とりあえず読んでみましょう。

C

1#include <stdio.h> 2 3int main(void) { 4 // 必要な変数を宣言 5 int data, max, min; 6 // 最大値をユーザに入力してもらう 7 scanf("%d", &max); 8 9 // ユーザから取得して、『(一度に)入力された個数が1である間』繰り返す 10 for (; scanf("%d", &data)==1;){ 11 // 取得したデータが最大値より大きいなら -> 最大値を更新する 12 if (data > max) max = data; 13 } 14 // ユーザから取得して、『(一度に)入力された個数が1である間』繰り返す 15 for (; scanf("%d", &data)==1;){ 16 // 取得したデータが最小値より小さいなら -> 最小値を更新 17 if (data < min) min = data; 18 } 19 // 最大値と最小値をそれぞれ出力 20 printf("%d\n",max); 21 printf("%d\n",min); 22 // 終了! 23 return 0; 24}

これを疑似コードとして書きだす。

[疑似コード] 0. 必要な変数を宣言する 1. 最大値をユーザに入力してもらう 2. ユーザから取得して、『(一度に)入力された個数が1である間』繰り返す 2.1. 取得したデータが最大値より大きいなら 2.1.1. 最大値を更新する 3. ユーザから取得して、『(一度に)入力された個数が1である間』繰り返す 3.1. 取得したデータが最小値より小さいなら 3.1.1. 最小値を更新する 4. 最大値の出力 5. 最小値の出力 6. 完了!

そしてこの疑似コードを実際に現実世界でやってみましょう。数学の問題の解き方なりマニュアルなりとしてやってみるのです。実際に値を考えてみてください。

データ群は an = { 19, 5, 40, 25 } とします。(a1 を 初項とする)

まず (0) は宣言なのでスルー。
(1)によって a1 つまり 19 が max に入る。max = 19 となります。

[データの状態] min = ???? max = 19

(2)では、「ユーザから取得して、『(一度に)入力された個数が1である間』繰り返す」ですが、
次の値であるa2 は 5 ですから、(一度に与えられるデータの)個数は1個。
なので条件を満たしているので (2.1)へ。

(2.1)では現在の最大値と取得したばかりのデータを比較しています。

max = 19 なので、data > max 、つまり 5 > 19 を満たすかどうか。
満たしませんね。5はどう見ても19より明らかに小さいので。

なので (2)に戻ります。で、a3 の値は 40。(一度に与えられるデータの)個数は1個なので(2.1)へ。

data > max 、つまり 40 > 19 はどうですか? 満たしますね。
なので(2.1.1)へ。
(2.1.1)では単純にmaxの値をdataの値に書き換えています。
よって、max = 40。

……とやっていき、a4 での 25 も同様にやる。
そうすると、最終的に max = 40 ということになります。

で、問題はここから。

次は最小値を計算しているようですが、与えられるデータanはすべて(2)で受け取ってしまっています。
つまり、『これ以上受け取るデータが無い』状態です。

で、(3)での条件式を見ても、「(一度に)入力された個数が1である間」です。
つまり、0でもダメだし、2以上でもダメです。
よって条件を満たさないため、何もしません。
そのまま(4)、つまりmaxの値を出力します。max = 40 なので 40を出力します。

で(5)ではminの値を出力しますが、計算していませんのでデフォルトの値に。
そしてそのまま(6)で終了。

ということで、

40 0

みたいなことになります。

ただし、今までの流れでminの値を指定していません。初期化もしていないし、maxのようにユーザ入力を受け取っているわけでもない。

よって、デフォルトの値になります。ただ、この初期化していない変数には、C言語の場合、不定値が入ります。環境とかによっては0だったり、でたらめな値(2223とか)が入っていたりします。

たまたまその環境の不定値が 0であれば、今回はminの計算はしていないので 0になります。
ですが、それ以外の環境では 2223 とかのようなでたらめな値になります。

今までの流れで問題点を考えてみてください。現実世界に照らし合わせてみてください。

一つ目。なぜmax, minを初期化していないのでしょうか。
上で述べたように、初期値を指定しない場合、不定値になります。
今回、maxがうまくいったのは、たまたまです。ただし意味はまったく違います。
だって、「最初の値を最大値と決めつけているから」です。暫定的に見なすことはあります。というか普通にします。ですが、「これは最大値として受け取るね」とは考えません。
それによってminの値がおかしくなるのです。

二つ目。データの個数は?
(2)によって「すべてのデータを受け取っている」ので、(3)に来る頃には「これ以上ない」となります。
よって受け取ろうにも受け取れません。

三つ目。minを初期化していないのはなぜか。
仮に(1)で適切にやって、(2)でも適切にやったとしても、minは初期化していないので、でたらめな値になっています。それによって、おそらく計算が合わないと思います。

たとえば、単純に最小値だけの処理だと考えてみてください。
流れは上記の疑似コードとします。(最大値云々の部分だけスキップすると考えて)

そもそも最小値とはなんでしょうか。
「最も小さい値」、つまり『一番小さい値』ですよね。
小さいとはなんでしょうか。

1と10 ならどっちが小さいでしょうか。そう1ですね。
では1と0なら? 0ですね。

と考えると、仮にminの初期値が0だと仮定しても、どうやっても必ず0が最小値になるはずです。
(与えられるデータ、anがすべて正の数であれば)

負の数があればそれになりますが、正の数だと0が最強!!!
ということは「更新が一切ない」ので常に0になる可能性が高いです。

ではどうするか。初期値を変えるのです。
初期値はなんでもいいですが、与えられるデータから考えます。

常に 0~200 の間なら、201 とかみたいな、明らかにデカい数字を与えます。
そうすれば、仮に最小値が 200 だとしても、200 < 201 は満たすのでちゃんと更新されます。

データを受け取るときは変数で一回一回でもいいですが、今回のような場合、現実世界で考えるとノートとかに一気に記録するはずです。

ヒントは、『変数』『配列』『for文』。

つまり、「基礎が出来ていない事」と『プログラミングの基本的な考え方』ができていない事が原因です。

[質問者さんが学ぶべきこと] ■ プログラミングとは何か ■ ロジックの考え方 ■ scanf関数の使い方( 引数や戻り値等 ) ■ 配列 ■ for文

投稿2021/10/27 07:47

BeatStar

総合スコア4962

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

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

0

先にfor (; scanf("%d", &data)==1;)maxの処理をするだけでループを回してしまっては、もう入力は残っていません

「1回目のループでmaxを処理して2回目でminを処理する」という発想そのものが誤りです。

投稿2021/10/27 01:38

maisumakun

総合スコア146018

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

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

ryuuabis

2021/10/27 07:06

回答ありがとうございます。
guest

0

ベストアンサー

プログラムは、上から順番に実行されます。
この場合、maxに19が入力され、つぎのforループ(maxの処理)で5, 40, 25が入力されmaxとの比較で、forループを抜けると、max=40が残ります。

次にforループ(minの処理)を行いますが、入力を行わない/入力が無いと、minのためのforループを抜けてしまいます。
従って、minは初期値のまま0が表示されます。
minも正しく処理したいのであれば、minのforループでも同じ数値(5, 40, 25)を入力する必要があります。 (minの初期値を設定するためのscanfも必要です。)

または、
初期値として scanf(.......); min=max; とし、
1つのforループの中で minと、maxの処理を行えば良いと思います。

投稿2021/10/27 01:00

yu-ima

総合スコア249

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

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

ryuuabis

2021/10/27 01:14

すみません、minにも同じ数値を入力させるには、初期値をどのようにすれば良いのでしょうか? #include <stdio.h> int main(void) { int data, max, min; scanf("%d", &max); for (; scanf("%d", &data)==1;){ if (data > max) max = data; } for (min=1; scanf("%d", &data)==1;){ if (data < min) min = data; } printf("%d\n",max); printf("%d\n",min); return 0; }
yu-ima

2021/10/27 01:40 編集

minのためのforループ(maxのforループ後)の前に scanf("%d", &mmin);を置いて この入力に19を入れ、minのforループで 5, 40, 25を順次入力すれは結果は正しく出ます。 しかし、 このような方法は、結果としては正しく出ますが 一般的には行いません。 scanf("%d", &max); min=max; for (; scanf("%d", &data)==1;){ if (data > max) max = data; if (data < min) min = data; } のようにするのが良いのではないでしょうか? 注. これが最良というわけではなく、他にもたくさんあります。
ryuuabis

2021/10/27 07:04

おかげさまで、出来ました。 ありがとうございました。。m(_ _)m #include <stdio.h> int main(void) { int data, max, min; scanf("%d", &max); min=max; for(;scanf("%d", &data)==1;){ if (data > max) max = data; if (data < min) min = data; } printf("%d\n",max); printf("%d\n",min); return 0; }
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問