プロが教える店舗&オフィスのセキュリティ対策術

http://oshiete1.goo.ne.jp/qa3853689.htmlにて質問した内容ですが、
想定していたソースの範囲内では解決しないことが分かりましたので、新規に立てさせていただきます。

下記でfgetsを使って入力した後についてですが、*2のgetcharを無視して、*1のscanfで入力を受け付けなくなります。
*2のgetscharについては、その個数を増やしても同様に無視されます。
これを解消する方法はないでしょうか?
ちなみにコンパイラはBBC、開発環境はVistaです。
なお、簡略のため#includeなどは省略しています。

#define SIZE 16384

void main(void){
 int mode,r;

 while(1){
  do{
   r = scanf("%d", &mode); //*1 return後に停止
   while(getchar() != '\n'){ };
  }while(r == 0)

  switch(mode){ //その他選択肢あり
   case 1:
    execute();
    break;
  }
 }
 return;
}

void execute(void){
 char moji[SIZE];
 char buf[SIZE];

 while(fgets(buf, sizeof(buf), stdin) != NULL){
  if(sizeof(moji) < strlen(moji) + strlen(buf))
   break;
  strcat(moji, buf);
 }

 while(getchar() != EOF){ }
 getchar(); //*2 これを無視して動作(scanfでも同様)

 return;
}

A 回答 (4件)

★フィルタ・コマンドですか。


・標準入力(stdin)でキーボードからの入力では必ず『改行』を含むように
 注意するしかないような気がします。
・過去に MS-DOS 用のフィルタコマンドをよく作成しましたが fgets で
 『改行』コードが最終行に追加されない場合を入力の終わりと判定する
 スマートな方法はないです。低水準の関数を使って直接読み取るように
 すれば可能ですが移植性も考え高水準の関数を使うべきです。
 元々低水準関数は処理系が高水準を実現するために用意されているだけで
 プログラマに利用するようには考えられていません。
・私の対策方法
 最終行に改行コードがなくて『^Z』+『Enter』を押すとまだ入力待ちに
 なるのためもう一度『^Z』+『Enter』を押して終わりと判定させるように
 入力側(人間)が気をつけるようにしています。
 ※ほかにもっと良い方法があれば私も乗り換えたいです。
・OS(Windowsなど)限定で利用するならAPI関数を直接呼び出して fgets と
 ほぼ同じ処理をする関数を自作すれば要求通りの動作が可能です。
 あまりお勧めではありませんが方法としてはあります。
 また conio.h の kbhit()、getch()関数を使って fgets 同等の関数を
 作り出す方法もあります。こちらも処理系や OS によって conio.h が
 用意されていない場合もありますので注意すべきです。
・さて、どうしますか?
    • good
    • 0
この回答へのお礼

暫定的には、入力画面やreadmeなどで注意を喚起し、あとは使用者に任せるしかありません。
ファイル入力への対応へ踏み切れれば、標準入力による入力方法を止め、ファイル入力のみに絞ることでエラーの発生を回避する方法を取りたいと思います。

まだ先の話ではありますが、将来的にはWin32 APIへ移行したいと思っているので、それまでは使用者に不便を強いるしかないかと。

長々と、ありがとうございました。

お礼日時:2008/03/11 23:15

★難しそう。


>できればこの状態でも正常に動作するようにしたいのですが、可能でしょうか?
 ↑
 feof()を使えば少しはマシになります。

// 実行
void execute( void )
{
 char moji[ SIZE ] = { 0 };
 char buff[ SIZE ] = { 0 };
 
 //EOF(^Z)になるまで、文字列を受け取る
 puts( "EOF(^Z)まで入力" );
 while ( !feof(stdin) && (fgets(buff,sizeof(buff),stdin) != NULL) ){
  if ( sizeof(moji) < (strlen(moji) + strlen(buff)) ) break;
  strcat( moji, buff );
 }
 puts( "フラッシュ" );
 while ( !feof(stdin) && (getchar() != EOF) ){
  ;
 }
 puts( "一時停止" );
 getchar(); //*2 これを無視して動作
 puts( "抜ける" );
}
これでも改行がない状態で^Zを入力するとwhile文を抜けませんが、
もう一度^Z+Enterキーを入力すると抜けるようにはなります。
feof()を使っているので『フラッシュ』のwhile文でループしません。

fgetsで標準入力から改行なしで入力の終わりと判定するのは難しそうです。
ファイルやリダイレクション入力なら正しく終わりを判定してくれますが、
標準入力(=キーボード)からは難しいので最終的に何を行いたいのかを補足して下さい。
もしかしたら別の解決策が見つかるかもしれません。

この回答への補足

最終的には、読み込んだ文字列を元に、禁則処理を適用して原稿用紙として換算することが目的です。
読み込む文字列は、基本的にHTMLファイルのソースで、設定次第では一般的なテキスト文章も利用可能な状態です。
前者の場合、入力後にタグを除去する操作を行っております。
現段階では非対応な状況ではありますが、将来的には標準入力(stdin)とファイル入力の両方に対応できればと考えております。

補足日時:2008/03/11 21:50
    • good
    • 0

★補足


>※while文のブロック後には『;』文字は記述できません。基本でしょ。
 ↑
 記述は出来ますが、意図しない動作をすることがあるので注意。
 『;』文字だけだとを空文として処理されます。
 エラーが出ないためバグを見つけにくくなります。
    • good
    • 0
この回答へのお礼

原因が分かりました。
fgetsで入力する際に、下記のように^Zの前に改行がない状態で入力していたようです。

fasdfasdfasdfas
fasdfasdf^Z

できればこの状態でも正常に動作するようにしたいのですが、可能でしょうか?

お礼日時:2008/03/11 20:09

★些細な記述ミスが数箇所発見。


>*2のgetscharについては、その個数を増やしても同様に無視されるようです。
 ↑
 無視されるとはどういう事ですか?
 一時停止しないでexecute()関数を抜けるのですか?
・『お礼』『補足』に些細なミスが数箇所あります。
 コンパイル時にエラーが出ませんか?
 下に私がデバッグしたソースを載せておきます。

サンプル:
#include <stdio.h>
#include <string.h>

#define SIZE 100

char moji[ SIZE ] = { 0 };
char buff[ SIZE ];

// 実行
void execute( void )
{
 //EOF(^Z)になるまで、文字列を受け取る
 while ( fgets(buff,sizeof(buff),stdin) != NULL ){
  if ( sizeof(moji) < (strlen(moji) + strlen(buff)) ) break;
  strcat( moji, buff );
 }
 puts( "フラッシュ" );
 while ( getchar() != EOF ){
  ;
 }
 puts( "一時停止" );
 getchar(); //*2 これを無視して動作
 puts( "抜ける" );
}

// メイン関数
void main( void )
{
 int mode, r;
 
 for ( ; ; ){
  do {
   puts( "入力:" );
   r = scanf( "%d", &mode );  //*1 1度目は「1」を入力
   while ( getchar() != '\n' ){;}
  } while ( r == 0 );
  
  puts( "選択枠" );
  
  switch ( mode ){  //その他選択肢あり
   case 1:
    execute();
    break;
  }
 }
}
※こちらでは一時停止しますけど。

原因:
>*2のgetcharを無視して、*1のscanfで入力を受け付けなくなります。
これは些細な記述ミスによると思います。
 間違い⇒『while(getchar() != '\n'){ };』
 正しい⇒『while(getchar() != '\n'){;}』
 ※セミコロンをブロック内に記述します。
 ※while文のブロック後には『;』文字は記述できません。基本でしょ。

最後に:
 締め切りが早すぎます。
 再回答しようとしたら書き込めなかった。
    • good
    • 0
この回答へのお礼

締め切りについては、申し訳ありませんでした。

サンプルで頂いたソースをC&Pの後、コンパイル、実行しましたが、
やはり*2のgetcharを無視して*1のscanfの場所で入力できなくなります。
「getcharの無視」については、「あるのにも関わらず、ない状況と同じ動作をする」という状況です。

while(~){~};については、do{~}while(~);と勘違いしていたようです。
しかしながら、while(~){~};でもコンパイルエラーは表示されなかったことを併記しておきます。

お礼日時:2008/03/11 20:04

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!