前提・実現したいこと
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ページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/10/27 01:03
2021/10/27 01:34
回答4件
0
なぜなのでしょうか
やることの筋道がしっかりと立てられていないから,ではないでしょうか.
コードを書き始めるよりも前に「何をどういう順序で実施していけば所望の動作を達成できるのか?」という事柄を確定させる:
例えば,以下のような手順をとれば良かろう,みたいな方針をしっかりと考えてみることです.
1. 初期化 : 「現在までの最小値」と「現在までの最大値」という変数を用意し,適切に初期値を与えておく. 2. メインの処理 : 【整数を1つ入力させ,その入力値に基づき「現在までの最小値」と「現在までの最大値」を更新する】という処理を複数回繰り返す. 3. 結果の表示 : 「現在までの最小値」と「現在までの最大値」を表示する.
この処理の大枠だけではまだ下記のような未定事項があるので実装できません.
- 「適切な初期値」ってのは具体的には何だよ?
- 「複数回の繰り返し」を抜ける方法は何か?
- 「複数回繰り返す」部分が1回も実施されない場合はあり得るのか? あり得るならば,何かそのケースへの対応が必要であろうか?
……といった事柄に全て決着をつけたら,あとはそのとおりに実装します.
投稿2021/10/27 01:23
編集2021/10/27 08:01総合スコア11996
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/10/27 01:26
2021/10/27 01:28
2021/10/27 01:46
2021/10/27 07:55
2021/10/27 08:04
2021/10/27 08:09
2021/10/27 08:25 編集
2021/10/27 08:37 編集
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
総合スコア4962
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
先にfor (; scanf("%d", &data)==1;)
でmax
の処理をするだけでループを回してしまっては、もう入力は残っていません。
「1回目のループでmax
を処理して2回目でmin
を処理する」という発想そのものが誤りです。
投稿2021/10/27 01:38
総合スコア146018
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
総合スコア249
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/10/27 01:14
2021/10/27 01:40 編集
2021/10/27 07:04
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。