- 締切済み
C言語・標準入力でquitを入力で終わるプログラム
C言語標準入力でquitを入力で終わるプログラムを作っているのですが うまくいきません #include <stdio.h> int main(void) { int i, n; double data[100]; printf("数字を入力してください。\n"); printf("入力を終えるときにはCtrl-dを押してください。\n"); n = 0; while (scanf("%lf", &data[n]) != EOF) { n++; } for (i=0; i<n; i++) { printf("data[%d] = %f\n", i, data[i]); } return (0); } と今はとりあえづ作ってみたのですが 今のままではCtrl-dでループから抜ける形になっています strcmp関数を使うとは思うのですが strcmp関数はchar型なのでエラーが出てしまいます; このやり方じゃないchar型にしてやり直さないといけないでしょうか; Linux CentOS gcc でやっています 標準入力で数字を入力しそれを格納 quitを入力するまで繰り返す quitを入力で終了、これまで格納していた文字列の表示 簡単なプログラムの流れとしては上記の感じです よろしくお願いします。
- みんなの回答 (13)
- 専門家の回答
みんなの回答
- Wr5
- ベストアンサー率53% (2173/4061)
終了しますね。>#12 hogehog12345670000004quit とか入力すると妙な挙動に見えるかも知れませんね。 標準入力に残る関係上しょうもないですかね。 まぁ、エラーケース考えるのは質問者さんに任せるとします。 # 勉強用だとエラー処理とか入っていなかったりとか多いですし。 # fgets()の戻り値もチェックしていなかったなぁ、そういえば…。
- Tacosan
- ベストアンサー率23% (3656/15482)
起動した直後に hogehogquit を入力するといきなり終了しちゃうような気がします>#11. まあ「そ~いう仕様」だと思えばいいだけですが.
- Wr5
- ベストアンサー率53% (2173/4061)
こんな感じですかねぇ…… インデントを全角空白でやっているのでコピペする場合はご注意を。 一応、CentOS6.5で動作確認はしましけど。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define MCH 8 #define N 20 int main() { int data[N]; int nc = 0, i, flag; char bff[MCH]; do { /* 入力 */ printf("data%d?:", (nc + 1)); fgets(bff,MCH,stdin); /* "quit"だったら抜け */ if(strcmp(bff,"quit\n") == 0) { break; } /* 数字以外があるか確認 */ for(i = 0,flag = 1;bff[i] != '\n' && bff[i] != '\0';i++) { if(!isdigit(bff[i])) { flag = 0; } } if(flag != 1) { printf("error:数字のみでお願いします。\n"); continue; } /* 5桁以上ならエラー(先のforループの結果、iは入力した文字数になっている) */ if(i > 5) { printf("error:5桁以内でお願いします。\n"); continue; } /* データ格納 */ if(i != 0) { data[nc++] = atoi(bff); } }while(nc < N); /* 結果表示 */ printf("データ:\n"); for(i = 0;i < nc;i++) { printf("data[%d]=%d\n", i, data[i]); } return 0; }
- Wr5
- ベストアンサー率53% (2173/4061)
先は長そうですねぇ…… >:27: error: ‘else’ without a previous ‘if’ >else if(!isdigit(bff)) のelseに流れる為のif文はどれでしょう? >:33: 警告: passing argument 1 of ‘strcpy’ makes pointer from integer without a cast … >strcpy(a,bff); char型に「文字列」は入れられません。 というか、この場合変数aに入っている謎の値がアドレスとして処理されます。(型が違うので怒られてますが) >:35: 警告: passing argument 1 of ‘atoi’ makes pointer from integer without a cast … >i=atoi(nc); atoi()の引数はchar *かと。ncでは…アドレス0~10に数字が入っていることになります。 # 型がおかしいからやっぱり怒られる。 >:48: error: expected ‘while’ at end of input 久しぶりに「{」と「}」の対応が取れていません。 do {に対応する}は一番最後のものです。 よって、main()が閉じていませんので… >:48: error: expected declaration or statement at end of input こう言われます。 さて、他のツッコミ満載を消化しましょうかね。 >if(!(strcmp(bff,"quit\n")==0||nc==N)) ncがNだった時に… >ch[nc++] = bff[0]; バッファオーバーフロー達成です。 ch[20]は安全に使える領域でしたか? >char ch[N],a; char型では値が入らない…と指摘済みですよね? >scanf("%5d",bff); %dで指定する場合は、結果を格納するアドレスを渡す必要があります。 bffはアドレスなのでまぁ、OKでしょう。 想定する動作はしませんが。 # bffからの連続する4バイトに「数値」が入ります。「数字」ではありませんのでご注意を。 # どう格納されるかは…エンディアン次第ですかね。(4バイトである保証もありませんが…まぁ、この場合どうでもいい話) >else if(!isdigit(bff)) 「isdigit()で1文字ずつ」と書いたかと思われますが…… 何より引数の型が違うかと。(char *がintになったんですかねぇ…) >printf("@ bff=%s",bff); >printf("@ atoi(bff)=%d\n",atoi(bff)); 入力のループの外にありますよ? それで正しいのですか?? >fget(bff,MCH,stdin); で数字を入力した場合は、まるっと捨てます。 # 後でscanf()しているから。 というかfgets()…ですよね?? なんというか、そろそろ回答例なコードでも乗せて強制終了した方がいいんじゃないか? とか思い始めてきた……。 勉強にはたぶんならないけど。
- Wr5
- ベストアンサー率53% (2173/4061)
>→数値=コンピュータで計算できる数字 >数字=人間語でコンピュータで計算できない >って言う認識なんですが…; おおむね合っている…かなぁ。 念のため、「数値 数字」などでWeb検索してください。 >→条件:数字以外入力時はエラー表示し、再入力・全角数字の場合入力時はエラー表示し、再入力 >というのもあるので エラー判定の追加があるようなので… イメージとして掲示した中の 入力内容をコピー(ch[nc]=入力内容(数値で保持なら数字=>数値変換)) の前で、入力した文字列が数字のみかどうかの判定処理を追加してください。 http://linux.die.net/man/3/isdigit のisdigit()で「1文字ずつ」判定していけばよいでしょう。 # 数字=>数値変換でエラーになったら…とかいう手もありますけどね。 # ただしatof()は使えないですが。sscanf()でもダメ…かなぁ…(先頭が数字だと…ね)
お礼
とりあえず 大まかな流れとしてはこんな感じですかね? #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define MCH 8 #define N 20 int main(){ char ch[N],a; int nc,quit,ic,b; char bff[MCH]; printf("入力(quit by quit):\n"); nc=0; do{ fget(bff,MCH,stdin); if(!(strcmp(bff,"quit\n")==0||nc==N)) { ch[nc++] = bff[0]; break; } else { scanf("%5d",bff); printf("error:5桁以内でお願いします。\n"); } else if(!isdigit(bff)) { puts("error"); } else { strcpy(a,bff); ch[nc]=a; i=atoi(nc); } while(!quit); printf("@ bff=%s",bff); printf("@ atoi(bff)=%d\n",atoi(bff)); printf("データ:\n"); for(ic=0;ic<nc;ic++) { b = ch[ic]; printf("ch[%d]=%d\n",ic,b); /*printf("ch[%d] = %f\n",ic,ch[ic]);*/ } return 0; } : In function ‘main’: :27: error: ‘else’ without a previous ‘if’ :33: 警告: passing argument 1 of ‘strcpy’ makes pointer from integer without a cast /usr/include/string.h:128: note: expected ‘char * __restrict__’ but argument is of type ‘char’ :35: 警告: passing argument 1 of ‘atoi’ makes pointer from integer without a cast /usr/include/stdlib.h:148: note: expected ‘const char *’ but argument is of type ‘int’ :48: error: expected ‘while’ at end of input :48: error: expected declaration or statement at end of input めっちゃエラー出てしまったんですけどね… これでも半分まで減らしましたが今出てるエラーは意味がわからなくて…
- Wr5
- ベストアンサー率53% (2173/4061)
>ch[]の値はどこでどんな感じで入れたら良いですか?; 数値で入れたいのか、文字で入れたいのか…どちらです? # とりあえず、「数値」と「数字」の区別はつきますか? >charじゃないほうが良いということはdoubleとかにしないとってことですかね…? 数値…であれば、int型の配列でいいんじゃないですかね? 文字として…ということならばchar型の二次元配列なりになると思いますが。 >あと条件で >5文字以上の場合入力時はエラー表示し、再入力 >というのがありまして nc=0; do{ fgets(bff,MCH,stdin); bffがquitじゃないか判定。 =>quitだったらループ脱出フラグ設定 else bffが5文字(5桁?)以内か判定 =>5文字以上ならエラーメッセージ表示 else 入力内容をコピー(ch[nc]=入力内容(数値で保持なら数字=>数値変換)) nc加算 ncが10か? =>10だったらループ脱出フラグ設定 }while(!quit); って感じですかね。 数字=>数値変換でエラーになる可能性もありますけど。 「"wktk"を数値にせよ。」とか言われても困るでしょう?
お礼
# とりあえず、「数値」と「数字」の区別はつきますか? →数値=コンピュータで計算できる数字 数字=人間語でコンピュータで計算できない って言う認識なんですが…; 数値…であれば、int型の配列でいいんじゃないですかね? 文字として…ということならばchar型の二次元配列なりになると思いますが。 →条件:数字以外入力時はエラー表示し、再入力・全角数字の場合入力時はエラー表示し、再入力 というのもあるので intですかね; nc=0; do{ fgets(bff,MCH,stdin); bffがquitじゃないか判定。 =>quitだったらループ脱出フラグ設定 else bffが5文字(5桁?)以内か判定 =>5文字以上ならエラーメッセージ表示 else 入力内容をコピー(ch[nc]=入力内容(数値で保持なら数字=>数値変換)) nc加算 ncが10か? =>10だったらループ脱出フラグ設定 }while(!quit); って感じですかね。 →ありがとうございます。ちょっとそのやり方でやってみますね;
- Wr5
- ベストアンサー率53% (2173/4061)
>データ: >ch[0] = ? >ch[1] = A >となって値が出てこなかったです; 出てきたら恐怖です。 >do{ >fgets(bff,MCH,stdin); >if(!(quit=strcmp(bff,"quit\n")==0||nc==N)){ >nc++; >} >} >while(!quit); のどこで、ch[]に値を入れているのでしょうか? あと…ch[]はchar型なので、入力した内容を数値として持つつもりなら >234 >345 234はともかく345は入りません。(char型には255まで…でしょう。signed charだったら127) さらに… >printf("ch[%d] = %c\n",ic,ch[ic]); %cで出力すると入力値によっては画面壊れたりしますよ。 # 表示できない文字コードだった…とか、コントロールコードだった…とか……。
お礼
ch[]の値はどこでどんな感じで入れたら良いですか?; あと条件で 5文字以上の場合入力時はエラー表示し、再入力 というのがありまして…記載するのを忘れていましたが… charじゃないほうが良いということはdoubleとかにしないとってことですかね…? #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define MCH 8 #define N 20 int main(){ char ch[N]; int nc,quit,ic,b; char bff[MCH]; printf("入力(quit by quit):\n"); nc=0; do{ fgets(bff,MCH,stdin); if(!(quit=strcmp(bff,"quit\n")==0||nc==N)){ ch[nc++] = bff[0]; } }while(!quit); printf("@ bff=%s",bff); printf("@ atoi(bff)=%d\n",atoi(bff)); printf("データ:\n"); for(ic=0;ic<nc;ic++) { b = ch[ic]; printf("ch[%d]=%d\n",ic,b); /*printf("ch[%d] = %f\n",ic,ch[ic]);*/ } return 0; }
- Wr5
- ベストアンサー率53% (2173/4061)
指摘漏れ。 >printf("str[%s] = %s\n",i,str[i]); 最初の%sで、アドレス0からの文字列を表示。 gccってことだからたぶん"(null)"で済むでしょう。 が、その次の%sで…str[0]の値がアドレスとして使用されて…ここでもセグメンテーションフォルト発動…でしょうね。 >char str[10]; では、入力された情報を保持し続けるには足りません。 >while(scanf("%s",str[n])){ >if(!(quit=strcmp(str,"quit\n") == 0 || n == 10)) でnが10になっていた時には手遅れです。 配列の添え字の範囲について再度勉強し直してください。 # char str[10]; # で確保された配列は… # str[0]~str[10]まで使えますか? # str[1]~str[10]でしったけ?
お礼
指摘と自分なりに考えて下記のようにしてみました。 #include <stdio.h> #include <string.h> #include <ctype.h> #define MCH 8 #define N 20 int main(){ char ch[N]; int nc,quit,ic; char bff[MCH]; printf("入力(quit by quit):\n"); nc=0; do{ fgets(bff,MCH,stdin); if(!(quit=strcmp(bff,"quit\n")==0||nc==N)){ nc++; } } while(!quit); printf("データ:\n"); for(ic=0;ic<nc;ic++) { printf("ch[%d] = %c\n",ic,ch[ic]); } return 0; } gccでコンパイラ時のエラーはありませんでした 実行 入力(quit by quit): 234 345 quit データ: ch[0] = ? ch[1] = A となって値が出てこなかったです;
- Wr5
- ベストアンサー率53% (2173/4061)
>error: expected declaration or statement at end of input 14行目と16行目が対。(問題なし) 18行目と22行目が対。(だけど途中のreturnで終了) 5行目のmain()開始の「{」と、12行目のwhile()ループ開始の「{」が片思い中です。 あと…… >char str[10]; >scanf("%s",str[n]) 入力された文字列を、どっか判らないアドレス(str[]は未初期化の変数なので入っている値は不定)に入れてね♪ ということで、コンパイルエラーを修正しても実行して入力した段階でセグメンテーションフォルトの魔法が発動でプロセス殺人事件が発生します。 犯人は……OSだっ!! # 真犯人は仕組んだプログラマーだ。
- Wr5
- ベストアンサー率53% (2173/4061)
>passing argument 1 of 'strcmp' from incompatible pointer type strとした時とstr[n]とした時で型が異なりますが、その辺りは理解してます? >while(scanf("%s",str[n])); >if(!(quit=strcmp(str,"quit\n") == 0 || n == 10)) scanf()で入力を受け取ったのはstr[n][0]からstr[n][9]の範囲。 strcmp()で比較したいのはどこですか? # あと、scanf()で受け取った時に改行文字入っていますか?? >error: expected 'while' at end of input while()の後にセミコロンありますが、正しいですか? というか、12行目にあるdoに対応するwhile()ってどれです? >error: expected declaration or statement at end of input 「{」と「}」の対応が取れていません。 main()の「{」(5行目)に対応する「}」がありません。 vimでも対応する括弧は色を変えて表示してくれるオプションがあったと思いますのでその辺り確認しましょう。 ちなみに、16行目と18行目が対、 20行目と22行目が対、 13行目と24行目が対になっています。 # 24行目の対がmain()の開始…なのでしょうから、13行目の対が無い(というかdoに対応するwhile()が不明)というのが問題なのでしょう。
お礼
すいません; 少し直してみました;;; #include <stdio.h> #include <string.h> int main(void) { int i,n,quit; char str[10]; printf("プログラムを終了するにはquitを入力してください\n"); n = 0; while(scanf("%s",str[n])){ if(!(quit=strcmp(str,"quit\n") == 0 || n == 10)) { n++; } for(i=0;i<n;i++) { printf("str[%s] = %s\n",i,str[i]); return 0; } gcc後のエラー↓ #ファイル名: In function 'main'* #ファイル名#:22: error: expected declaration or statement at end of input
- 1
- 2
お礼
すいません 長々付き合ってもらってしまって… 申し訳な過ぎるので もお解答例を頂いて自分で勉強しようかと思ったのですが… ご迷惑じゃなければ解答例を頂けないでしょうか 本当に長々付き合わせてすいませんでした