こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

締切り済みの質問

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を入力で終了、これまで格納していた文字列の表示

簡単なプログラムの流れとしては上記の感じです
よろしくお願いします。

投稿日時 - 2014-09-08 12:34:29

QNo.8746784

すぐに回答ほしいです

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(13)

ANo.13

Wr5

終了しますね。>#12

hogehog12345670000004quit

とか入力すると妙な挙動に見えるかも知れませんね。
標準入力に残る関係上しょうもないですかね。
まぁ、エラーケース考えるのは質問者さんに任せるとします。
# 勉強用だとエラー処理とか入っていなかったりとか多いですし。
# fgets()の戻り値もチェックしていなかったなぁ、そういえば…。

投稿日時 - 2014-09-11 15:04:30

ANo.12

起動した直後に
hogehogquit
を入力するといきなり終了しちゃうような気がします>#11.

まあ「そ~いう仕様」だと思えばいいだけですが.

投稿日時 - 2014-09-11 12:43:25

ANo.11

Wr5

こんな感じですかねぇ……
インデントを全角空白でやっているのでコピペする場合はご注意を。
一応、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;
}

投稿日時 - 2014-09-10 15:28:38

ANo.10

Wr5

先は長そうですねぇ……

>: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()…ですよね??




なんというか、そろそろ回答例なコードでも乗せて強制終了した方がいいんじゃないか?
とか思い始めてきた……。
勉強にはたぶんならないけど。

投稿日時 - 2014-09-10 14:22:31

お礼

すいません
長々付き合ってもらってしまって…

申し訳な過ぎるので
もお解答例を頂いて自分で勉強しようかと思ったのですが…

ご迷惑じゃなければ解答例を頂けないでしょうか

本当に長々付き合わせてすいませんでした

投稿日時 - 2014-09-10 14:53:42

ANo.9

Wr5

>→数値=コンピュータで計算できる数字
>数字=人間語でコンピュータで計算できない
>って言う認識なんですが…;

おおむね合っている…かなぁ。
念のため、「数値 数字」などでWeb検索してください。

>→条件:数字以外入力時はエラー表示し、再入力・全角数字の場合入力時はエラー表示し、再入力
>というのもあるので

エラー判定の追加があるようなので…
イメージとして掲示した中の
   入力内容をコピー(ch[nc]=入力内容(数値で保持なら数字=>数値変換))
の前で、入力した文字列が数字のみかどうかの判定処理を追加してください。

http://linux.die.net/man/3/isdigit
のisdigit()で「1文字ずつ」判定していけばよいでしょう。
# 数字=>数値変換でエラーになったら…とかいう手もありますけどね。
# ただしatof()は使えないですが。sscanf()でもダメ…かなぁ…(先頭が数字だと…ね)

投稿日時 - 2014-09-09 17:10:10

お礼

とりあえず
大まかな流れとしてはこんな感じですかね?


#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

めっちゃエラー出てしまったんですけどね…
これでも半分まで減らしましたが今出てるエラーは意味がわからなくて…

投稿日時 - 2014-09-10 13:51:51

ANo.8

Wr5

>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"を数値にせよ。」とか言われても困るでしょう?

投稿日時 - 2014-09-09 15:25:10

お礼

# とりあえず、「数値」と「数字」の区別はつきますか?

→数値=コンピュータで計算できる数字
数字=人間語でコンピュータで計算できない
って言う認識なんですが…;

数値…であれば、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);

って感じですかね。

→ありがとうございます。ちょっとそのやり方でやってみますね;

投稿日時 - 2014-09-09 16:39:53

ANo.7

Wr5

>データ:
>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で出力すると入力値によっては画面壊れたりしますよ。
# 表示できない文字コードだった…とか、コントロールコードだった…とか……。

投稿日時 - 2014-09-08 16:40:03

お礼

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;
}

投稿日時 - 2014-09-09 15:03:31

ANo.6

Wr5

指摘漏れ。

>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]でしったけ?

投稿日時 - 2014-09-08 14:40:33

お礼

指摘と自分なりに考えて下記のようにしてみました。


#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

となって値が出てこなかったです;

投稿日時 - 2014-09-08 16:04:29

ANo.5

Wr5

>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だっ!!
# 真犯人は仕組んだプログラマーだ。

投稿日時 - 2014-09-08 14:33:57

ANo.4

Wr5

>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()が不明)というのが問題なのでしょう。

投稿日時 - 2014-09-08 14:11:56

お礼

すいません;
少し直してみました;;;

#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

投稿日時 - 2014-09-08 14:25:51

ANo.3

Wr5

"quit"を受け取る場所がないので、今のままではどうにもなりませんね。
scanf()で一度文字列として受け取り、"quit"でない場合はsscanf()で値として取り込む。
ってところでしょうかね。

"quit"のみなのか、"Quit"とか"quit."とか許容するかでいろいろ変わりますけど。

>quitを入力で終了、これまで格納していた文字列の表示

「文字列」ではなく「値」の表示になっていますがそこらヘンはOKですか?

投稿日時 - 2014-09-08 13:05:46

お礼

quitのみで大丈夫です;
すいません説明不足でした;

文字列じゃなくて値でOKです
すいません;;;

投稿日時 - 2014-09-08 13:48:39

ANo.2

考え方としては、文字入力のところをすべて、charの配列に入力するようにして、
"quit"でなければ、atof関数でdouble型に変換するという方法にプログラムを
書き換えてください。

投稿日時 - 2014-09-08 13:00:00

お礼

atof関数ですか
atof関数は使ったことなかったので
ちょっとggってみます;

投稿日時 - 2014-09-08 13:49:44

ANo.1

>strcmp関数を使うとは思う

たぶん、そうでしょうね。

>strcmp関数はchar型なのでエラーが出てしまいます

どこがchar型であると思われていますか?

また、エラーが出る、とは、
どんなコードを書いて
何をしたときに
どんなエラーが出るのですか?
そこを具体的に説明しないと、
ここにいる人たちは超能力者ではありませんので、
質問者さんの状況は何もわかりません。

投稿日時 - 2014-09-08 12:39:03

お礼

そうですよね;すいません;
色々わからなかったので
はじめっからやり直してみました;



#include <stdio.h>
#include <string.h>

int main(void)
{
int i,n,quit;
char str[10][10];

printf("プログラムを終了するにはquitを入力してください\n");
n = 0;

do
{
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でのコンファイル時のエラー↓

#ファイル名#:15:警告:passing argument 1 of 'strcmp' from incompatible pointer type
/usr/include/string.h:143: note: expwcted 'const char *' but argment is of type 'char (*)[10]'
#ファイル名#:24: error: expected 'while' at end of input
#ファイル名#:24: error: expected declaration or statement at end of input

こんな感じになってしまいました;
C言語は今月入って初めてやるので本当に意味が…
すいません;

投稿日時 - 2014-09-08 13:52:45

あなたにオススメの質問