ページ 1 / 1
表示が思い通りにできません
Posted: 2010年1月11日(月) 01:55
by あがぺん
規約に目を通しましたが初投稿なのでいたらない点があったら申しわけありません。
タイトルは『表示が思い通りにできません』となっておりますが、実際はなんと文字におこせばよいのかわからなかったので適切な表現ではなかったかもしれませんが、本文でしっかり質問内容を説明したいと思いますのでよろしくおねがいします。
今回質問したいのは構造体に対する文字入力を、何度も繰り返し行うというプログラムです。
自分のつくったプログラムは以下のものです。
#include <stdio.h>
typedef struct {
char moji1[20];
char moji2[20];
} list;
int main(void)
{
list std[10];
int i;
int k = 0;
for( i = 0; k == 0; i++) {
printf( "文字列1:" ); gets(std.moji1);
printf( "文字列2:" ); gets(std.moji2);
printf( "続けて入力するなら0,しないならその他:" );
scanf( "%d", &k);
putchar( '\n' );
}
return(0);
}
しかし上記のプログラムの表示結果は
文字列1:入力された文字列
文字列2:入力された文字列
続けて入力するなら0,しないならその他:0
文字列1:文字列2:入力された文字列
続けて入力するなら0,しないならその他:0
文字列1:文字列2:入力された文字列
続けて入力するなら0,しないならその他:1
というものになります。
そして私が皆様に質問したい部分は、表示結果の2度目以降の入力時で文字列1:文字列2:と並んで表示されてしまう箇所になります。
私が求めている表示結果は1度目の入力時の画面が何度も続く(文字列1:と文字列2:の間にしっかりと改行が入る)というものなのですが、どのようにプログラムを変更すればよいのでしょうか。
1度目の入力は問題がないところをみると、やはりfor文の判定部もしくはscanf()による入力が問題なのかと考えましたが自分では解決まで至ることができませんでした。
Cの知識は学校でまだ1年も勉強していないのでそんなに多くあるとはいえません。
今回の問題を理解し、解決できるようにお力添えお願いいたします。
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 03:21
by トントン
キーボードからの入力というのは、一度入力バッファという場所に格納され
格納されたものを読み込んでいきます。
バッファの中というのは空っぽなのが理想なのですが、空っぽだという確証がありません。
また、入力バッファの中身を読み込んでいくとバッファの中身がクリアされるのですが
処理によってはクリアされない場合があります。(詳しくはググってください)
ですので、今回は2回目の処理時に、バッファの中身に何かが残っていてそれを読み込んでしまい
2回目の処理のgets(std.moji1)が勝手に処理されてしまっていると考えられます。
入力処理をする前に
rewind(stdin)
または
fflush(stdin)
を入れることでバッファの中身をクリアすることができます。
C99の規格ではどうなっていたか忘れましたが、
visual studioを使っているのであれば上記の処理を入れることで解決できるはず!です。
まぁ、多分嘘が混じっていると思いますので、調べてみるのが一番かと。
または他の方が補足してくれると思います。
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 03:41
by Dixq (管理人)
トントンさんがお答えになっているので、補足というか参考サイトなどよければどうぞ
scanfとバッファに残るものとか
http://www.google.co.jp/search?hl=ja&so ... =&aq=f&oq=
fflushでバッファクリアとか
http://www9.plala.or.jp/sgwr-t/lib/fflush.html
未定義にならずにバッファクリアをする方法があるのかどうか知りませんが、
必ず改行コードが最後に来るのなら、getcharで改行コードが来るまで読み飛ばしてもいいですね。
後、トピックのタイトルについては原因が解らない場合は何と書けばいいのか解らないですよね。
今回の場合は
「scanfによる入力トラブル」とか「scanfによる不具合の解消方法について」みたいな感じでどうでしょう。
しかしscanfが原因かどうか最初は解らないでしょうから、特に神経質に題名にこだわらなくても大丈夫ですよb
後質問とは関係ないですが、
for( i = 0; k == 0; i++)
これは
for( i = 0; k == 0 && i < 10; i++ ) {
の方が安全じゃないですかね?
後、文字列は20文字以上入るとアウトなので、その辺も注意かも
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 08:10
by box
fflushは標準出力に対して使う関数です。
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 09:57
by さかまき
>fflushは標準出力に対して使う関数です。
少なくとも私は、stderrやFILEに対しても行っています。またVC6のMSDNを見ると
fflush 関数はストリームをフラッシュします。stream に結合されているファイルが出力用に開いている場合は、
fflush はストリームに結合されているバッファの内容をそのファイルに書き込みます。
ストリームが入力用に開いている場合は、バッファの内容をクリアします。
となっており標準出力以外でも使えるみたいです。
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 10:07
by box
>fflushは標準出力に対して使う関数です。
これは誤りでした。
fflushは出力ストリームに対して使う関数です。
が正しいです。
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 10:18
by フリオ
MSDNは、あくまでマイクロソフトが提供する開発環境を使用するためのリファレンスであって、
Cの標準のリファレンスでは有りません。
Cの標準規格では、fflush(stdin)の動作は、未定義です。
また、rewind(stdin)も、テキストファイルなどをリダイレクトすると、期待しない動作をします。
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 11:15
by たかぎ
私も自サイトでこの件については記述しています。
http://www.kijineko.co.jp/tech/supersti ... tream.html
処理系不明ですので、一般論としては、出力ストリーム以外をfflushに指定した場合の動作は未定義としかいえません。
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 12:33
by あがぺん
多くの回答ありがとうございました。
しかし私はまだ学生であり、fflushなるものを習っていないので今回使うことを見送りたいと思います。
今回私がとりくんでいる問題は、構造体に任意の回数入力するというものなので構造体に入力ということ以外はとくに制約はないのですが何か良い方法はありませんか。
せっかく皆様が回答してくれたのですが再び質問することになって、申し訳ありませんがお願いします。
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 12:37
by Dixq (管理人)
習って無くてもガシガシ知らないことにチャレンジしていく方が良いと思いますよ。
といっても今回の場合は適切な方法ではない可能性もあるので、
別な対策を取った方がいいかもしれませんが。
全て文字列でscanfしてやり、atoiでint型に変換してやればどうですか?
int a;
char str[10];
scanf("%9s",str);
a = atoi(str);
こんな感じでaに数値が入ります。
後、私が上で言ったgetcharを使う方法はどうですか?
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 13:23
by non
必ず文字を入力するのなら・・・
printf( "文字列1:" );
do{
gets(std.moji1);
}while(std.moji1[0]=='\0');
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 13:27
by あがぺん
管理人さんのいうgetcharをやってみようと思ったのですがうまく構成できませんでした。
自分の力不足でできないようです。
そして自分で調べてみたのですが、scanfの後にgetchar()をつけると上手くいくというのを見つけたのですがこれは管理人さんのとは少し違いますよね?
実際つけてみたらちゃんと表示されたのですが、この方法でなにかまずい点はありますか。
何度も質問になってしまいますが、もう少しで解決できそうなのでよろしくお願いします。
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 13:43
by Dixq (管理人)
私が言いたかったgetcharの使い方はこのような感じです。
#include <stdio.h>
int GetInputString( char str[ ], int n ){
int c,Cnt=0;
while( 1 ){
c=getchar(); //キーボード入力から一文字取ってくる
if( c==EOF || c=='\n' ){ //終端か改行なら
str[Cnt] = '\0'; //終端記号を入れ
return 0; //正常終了
}
if( Cnt>=n-1 ){ //もうこれ以上入れられなかったら
break; //抜ける
}
else{ //まだ入れられるなら
str[Cnt] = (char)c; //入れて
Cnt++; //カウントアップ
}
}
str[Cnt]='\0'; //抜けたらそこに終端記号を入れ
while( (c=getchar())!=EOF && c!='\n' ); //終端か改行が来るまで読み飛ばす
return -1;
}
int main(){
char Str[8];
if( GetInputString(Str, 8) == 0 ){
printf("入りました\n");
} else {
printf("全部入りませんでした\n");
}
printf("[%s]\n",Str);
return 0;
}
GetInputStringを使えば指定したバイト数以上データが配列に入る危険性もありませんしエンターを押すごとに区切って
バッファから読み込めると思います。
この関数の返り値を見れば指定サイズ内に収まったかどうかもわかります。
もっと簡単な方法があるかもしれませんが・・。
後scanfと正規表現を使って適切に読み飛ばすことも出来ると思いますが、正規表現を知らないとちょっと意味不明かもしれない・・
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 13:52
by Dixq (管理人)
Re:表示が思い通りにできません
Posted: 2010年1月11日(月) 20:38
by あがぺん
管理人さん本当にありがとうございました。
なんとか自分なりに整理もつき、解決に至れたと思います。
ありがとうございました。