• 締切済み

滝のように流れる・・・・・

学校の宿題なので、先生に見つかったら怒られそうですが・・・。みつかりませんように☆ このプログラムを実行したら滝のように流れます(汗;)どこを直せばよいのでしょうか。  キーボードから入力した値(整数)を5つのランクのうちのどのランクに属するかを 表示するプログラム。ランクは1=0~20,2=21~60,3=61~70,4=71~80,5=81~100とする。 #include <stdio.h> void main(void) { int x; scanf("%d",&x); printf("Data;%d",x); while(x>=0 || x<=100){ if(0<=x && 20>=x)printf("%dはランク1です。",x); else if(21<=x && 60>=x)printf("%dはランク2です。",x); else if(61<=x && 70>=x)printf("%dはランク3です。",x); else if(71<=x && 80>=x)printf("%dはランク4です。",x); else if(81<=x && 100>=x)printf("%dはランク5です。",x); else if break; } } また、もっと簡潔に書けるプログラムがあったら教えてください。よろしくお願いします。

みんなの回答

  • ret
  • ベストアンサー率40% (8/20)
回答No.9

すみません。printfを出力するだけの関数を別に作っていただけです。 実際は下のプログラムと同じ事です(^^;。 int main(void) { int value; char buf[16]; while(1){ printf("Data = "); fgets(buf, 16, stdin); value = atoi(buf); if((0 <= value)&&(value < 21)) printf("%dはランク1です\n", value); else if(value < 61) printf("%dはランク2です\n", value); else if(value < 71) printf("%dはランク3です\n", value); else if(value < 81) printf("%dはランク4です\n", value); else if(value < 101) printf("%dはランク5です\n", value); else break; } return 0; } valueはint型の変数、bufはchar型で16個の配列。 scanfの変わりにfgetsを使っています。 fgetsは本来ファイルから読み込む関数なのですが、 3つめの引数にstdinを指定するとキーボードからの読み込みに変わります。 (scanf, gets 関数を使いたくないので、fgetsを用いました。) fgetsの引数として、buf, 16, stdin の3つを指定していますが、 bufは&buf[0]とすることと同じです。 2番目の引数として、(今回は16)入力の最大文字数を指定します。 それ以上の文字が入力されても、切り捨てて無視します。 atolはcharから整数型に変更する関数です。 文字としての"123"から数字としての123に変えてくれます。 else if(value < 61) として、value >= 21 を条件に入れていません。 これは21未満の数は初めのifの条件に合致するので、 else if(value < 61)にくる数はかならず21以上であるからです けれど、とあることでこのプログラムは問題です。 別に暴走とかはしませんよ(^^;。 プログラム上に問題はないのですが、 仕様に合致しないときがあります。 (それはプログラム上の問題ですよね…m(_ _)m)

niconico-pun
質問者

お礼

ご丁寧にありがとうございます。 これから、C言語を学んでいく上で役立てたいと思います。

  • ret
  • ベストアンサー率40% (8/20)
回答No.8

scanf を使う上で問題は複改です。 もし、whileループの中で > scanf("%d",&x); を使うとするなら無限ループに陥るでしょう。 因みにgetsも用いるべきではありません。 gets(char*)は入力に対する制御がありませんから、 char buf[16]とした配列に256文字を入力されたとき、 動作不定に陥ります。 (実際に1994年にクラッカーによりgets関数を使ったネット上のプログラムが 狙われ問題になりました。) 現在はgetsは一般に「用いてはならない関数」となっています。 (よく出来たコンパイラはgetsを使っているだけで warningを出してくれます(^^;) もし私がプログラムを書くとするなら #include <stdio.h> #include <stdlib.h> void print( int value, int rank ) { printf("%dはランク%dです\n", value, rank); } int main(void) { int value; char buf[16]; while(1){ printf("Data = "); fgets(buf, 16, stdin); value = atoi(buf); if((0 <= value)&&(value < 21)) print(value, 1); else if(value < 61) print(value, 2); else if(value < 71) print(value, 3); else if(value < 81) print(value, 4); else if(value < 101) print(value, 5); else break; } return 0; } とするかな?(^^;。 併し、上のプログラムは一つだけ問題があります…。 あえて直していませんが、さて…。 何処に問題があるでしょう?

niconico-pun
質問者

お礼

全くわかりません・・・fgets、 value、bufなど見たことないものがたくさんで・・・。 ほんとにC言語初歩の初歩しか知らないので。。。ごめんなさい。

noname#4564
noname#4564
回答No.7

  瑕疵(バグ)のないプログラムの条件のひとつに「必ず終了すること」というのがあります。 このプログラムはその条件を満たしていません。 > scanf()関数はよほどのことがない限り使わない方がいい 実務(実践)の世界ではおっしゃる通りでしょうが、市販の書籍、特に初心者向けのプログラム例のほとんどがscanfで記述されているのが現実です。  

niconico-pun
質問者

お礼

ありがとうございました。参考にさせていただきます。

  • shige_70
  • ベストアンサー率17% (168/946)
回答No.6

scanf()を使っているようですが、これは学校で教わったのでしょうか? 専門家として助言しますが、scanf()関数はよほどのことがない限り使わない方がいいです。 理由は、この関数の機能は複雑で、使いこなすのが難しいのと、人間の入力だとミスなど不確定要素があるのでこれをscanf()に掛けたときに予想外の動作をすることがあるからです。 このばあいは、scanf("%d",&x); の代わりに char buf[BUFSIZ] ; gets( buf ) ; x = atoi( buf ) ; とかくと良いでしょう。

niconico-pun
質問者

お礼

はい。 scanf()は学校で教わりました。 使わない方がいいなんて、先生は全くいってなかったのに・・・ヾ(-д-;)助言ありがとうございました。 ただ、下のほうに書いてくださったものはまだならっていません。 これはscanf()の代わりにそのまま入れて大丈夫なのでしょうか。

  • madman
  • ベストアンサー率24% (612/2465)
回答No.5

1.0-100の範囲内で入力すれば、ランク表示。それ以外の数値で終了。としたいのでしょうか? 2.それとも、実行後一度だけ入力して、ランク表示その後にプログラム終了でしょうか? それによって処理が変わりますよ。 scanf:これは、数字の入力をしていますね。 printf:入力した数字を表示していますね。 while(x>=0 || x<=100):xの数値が0以上100未満のあいだ無限にループしますね。 if:各ランクを表示しますね。 else if break;:ランク外ならwhileの無限ループから抜けますね。(この行コンパイルエラーじゃない?普通ならelse break;) さてここで問題です。 ランク外の場合しか(else break)、ループを抜けませんから、ランク内の場合は無限ループですね。 1.のプログラムを書くなら、whileの中にscanf、printfを書きましょう。 2.のプログラムを書くなら、whileは不要です。また、else if break;も不要です。

niconico-pun
質問者

お礼

1、のようにしたいです。 そうです。else break;です。間違えてました。ごめんなさい。 while の中にscanf printfを入れるなんて、全然思いつきませんでした(@∇@)ありがとうございました

  • takscape
  • ベストアンサー率57% (15/26)
回答No.4

No.3です。 ループの条件は、  0<=x かつ x<=100 ではなく、  0<=x または x<=100 でしたね。 失礼しました。 しかしながら、入力として 0から100の間の値を 与えると無限ループするのはお分かり いただけると思います。

niconico-pun
質問者

お礼

そうですよね。ループから抜け出さないから・・・。ありがとうございます。

  • takscape
  • ベストアンサー率57% (15/26)
回答No.3

while文をよくご覧になってください。 このブロックが実行されるのは、   0<=x かつ x<=100 の場合ですが、 whileブロックを抜ける条件は、 xが「0から100までの範囲に無いこと」ですね。 つまり、このループに入ってしまったが最後、 二度と抜けられません。 そもそも、while文を用いる必要性も無いように 思われますが・・・。 また、余談ですが、scanf関数はあまりお使いに ならない方がよろしいかと存じます。 パラメータが比較的複雑で書き損じやすく、また 不正な入力が与えられた場合の処理も困難だからです。 通常は、gets関数などを用います。

niconico-pun
質問者

お礼

while文は用いないのですか。。。gets関数というのはまだ習っていないのでどんなものかよくわかりません。だからscanf()を用いたのですが。上記の方も書かれているようにあまり使わない方がよさそうですねぇ。知りませんでした。ありがとうございました。

  • mrumesuke
  • ベストアンサー率45% (254/557)
回答No.2

whileの使い方を理解していないようですね。 まずは考え方のヒントだけ。 ・whileは何をする命令ですか? ・このwhileの終了条件は何ですか? while(x>=0 || x<=100){ ... } ・変数xの値が変化するのはいつですか?

niconico-pun
質問者

お礼

はい。全く理解していません。 ・whileは条件式に当てはまる間ループする・・・と思っているのですが。 ・終了条件は、0以上100以下それ以外の数値が入力されたとき? ・Xの値が変化はscanfの入力によるのじゃないのですか。。。 ごめんなさい。C言語ほとんどわかりません・・・。ありがとうございました

  • liar_adan
  • ベストアンサー率48% (730/1515)
回答No.1

whileループの中で、xの値が変わっていないのだから、無限に回っちゃいます。 解決策としては、ループの中でxの値を変える操作をすればいいわけです。 つまりscanfもループの中に入れると解決します。 (余談:その際、whileの条件節も「常に真」でいいような…) それから、最後のelse if break;というのは書き間違いだと思いますが、ifは要りません。

niconico-pun
質問者

お礼

おはようございます。whileループの中で、xの値を変えればいいのですか。ありがとうございます。助かりました

関連するQ&A