こんにちは。
あるプログラムを作っていると、次のような問題が起きてしまいました。
簡単なプログラムを例にして、説明したいと思います。

#include<stdio.h>
#include<conio.h>
#include<ctype.h>

void main(void)
{
char ch;
int i;
do{
ch=getch();
putchar(toupper(ch));
}while(ch!='q');
printf("\n");
scanf("%d",&i);
}

これはgetch()関数を使い入力された文字を大文字にして画面上に出力するものです。(qが入力されるまで)
その後に、意味はありませんが変数iに整数を入力して終了する。
ここで、問題になってくるのがこのプログラムを実行して、abcdefqと入力していくと、画面上にはABCDEFQと表示されます。そして、qが入力されたことでdo文が終了して改行が行われます。次にscanfによりいったん入力待ちになります。
この時、まだ、なにも入力していないにも関わらず、最後にgetchにより入力したqが表示されてしまいます。
qを消してscanfの入力をすればいいのですが、この問題を何とか解決したと思い質問しました。
scanfの後にgetchar()を使うときはscanf入力時の'\n'に注意が必要だということはわかるのですが、上に述べたような問題はこれに似ているのでしょうか?
参考書をみたり自分でもいろいろ試してみたのですがどうもうまくいきません。

どなたか、解決策を知っていたら是非教えて下さい。
できれば、getch()とscanfがどのように作用してこのようなことが起きてしまっているのか説明して頂けたら幸いです。
お手数ですが、みなさま、よろしくお願いいたします。

このQ&Aに関連する最新のQ&A

A 回答 (5件)

何か問題が正確に伝わっていなかったりするみたいですね(苦笑)



環境は Windows9X 系でしょうか。
この環境下では、getch と scanf を近いところで使うと問題が起きるんですよ。
OS が呼び出す ReadFile() が、getch() が拾ったはずのキーのキーアップイベントを、もう1度押されたと誤認するようです。
(NT系では正常に動作するそうです)

この問題は、scanf の代わりに cscanf を使うか、scanf を使う前に __flush_win95_keyup_events() を呼び出すことで回避できます。

1度試してみて下さい。
    • good
    • 0
この回答へのお礼

ご回答有難う御座います。
はい、環境はWindows98です。OSの問題があったのですね!!
勉強になりました。早速試してみたいと思います。

勉強中なもので、また、みかけたらご指導の程宜しくお願い致します。

また、回答してくださったみなさま、質問の際、環境について説明を書き落としてしまい申し訳ありませんでした。

お礼日時:2001/12/21 15:36

こんにちは。

itohhといいます。

leaz024さん、こんにちは。
初めて知りました!わたしの環境がWinNT&2000なのでそういうことは気がつきませんでした。
もちろん、WinNT&2000で確認してみたところ、leon-10さんが言われている現象は出ないんですよ。

わたしも勉強になりました。ありがとうございます。
    • good
    • 0
この回答へのお礼

2度目のご回答有難う御座います。
わたしの方が、OSによる問題があるとはわからなかったもので、色々説明不足になってしまい申し訳ありませんでした。

お礼日時:2001/12/21 15:48

こんにちは。

itohhといいます。

解決策としては、ほかの方がアドバイスしているので。

>できれば、getch()とscanfがどのように作用してこのようなことが
>起きてしまっているのか説明して頂けたら幸いです。
これは、「getch()とscanf」の関係で起こっているわけではありません。

do whileループでは、ループの最後で次のループを行うかを判定します。
そのため、getch関数で「q」が入力された後にputcharで出力され、その後、
ループの終了条件を判定します。

>do{
>  ch=getch();       <-「q」を入力する。
>  putchar(toupper(ch));  <-「Q」を出力する。
>}while(ch!='q');       <-ループ終了条件の判定。

回答者No.1の方の方法で行うのが、スマートな方法だと思いますよ。
    • good
    • 0
この回答へのお礼

ご回答有難う御座いました。
まず始めに、質問が悪くてすいません。
回答して頂いたことは、理解できます。もう一度説明しますと、
doループでは後判定なので、仮にabcqと入力すると、getch()では入力した文字が画面に出力されない為、画面にはABCQと表示されてscanfの入力待ちになります。ここで、画面にQ大文字のQが表示されてしまうのは構いません。しかし、この大文字のQ以外に小文字のqが表示されてしまうのです。
この小文字のqが表示されてしまうのが気になるのです。バックスペースでこのqを消してから希望の入力値を入れることはできるのですが、できればこのqを表示したくありません。何とかならないでしょうか?
あまりうまく説明できていないかもしれません。
お手数ですが、短いプログラムなので、試していただけると幸いです。どのようなことが起こってしまか分かっていただけると思います。
申し訳ありません。
また、アドバイスがありましたら、宜しくお願い致します。

お礼日時:2001/12/20 17:31

入力バッファーをクリアーするためなら、つぎの文をscanfの前に入れるとよいでしょう。



fflush(stdin);
または
rewind(stdin)

先頭に#include <stdio.h>があれば結構です。
以上。
    • good
    • 1
この回答へのお礼

ご回答有難う御座います。
scanfのあとにgetchar()関数を使う時には、入力バッファをクリアーする為に('\n'をクリアーする)rewind(stdin)やfflush(stdin)を使うのは分かります。
この場合はその方法用いても解決できませんでした。
すいません。なにか分かりましたら、また、宜しくお願い致します。

お礼日時:2001/12/20 17:20

void main(void)


{
char ch;
int i;
ch=getch();
while(ch!='q') {
putchar(toupper(ch));
ch=getch();
}
printf("\n")
scanf("%d",&i);
}
とすればよいのでは?
    • good
    • 0
この回答へのお礼

ご回答ありがとうございました。
上のプログラムはqが入力された時は大文字のQが出力されないでscanf文に行くだけになってしまい。scanfで入力する前にqは画面に出力されてしまうのです。
すいません。

お礼日時:2001/12/20 14:03

このQ&Aに関連する人気のQ&A

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

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qvoid main(void){...}だとDosWindowが開くので

わざわざWindowsアプリにして以下のようにするしかないのでしょうか?

LONG WINAPI WinProcedure(HWND hW,UINT wM,UINT wP,LONG lP)
{
//ここに宣言を置く
switch(wM)
{
case WM_CREATE:
//ここに処理を置く
return 0;
default:
return(DefWindowProc(hW,wM,wP,lP));
}
}
WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int nCS)
{
WNDCLASSwc;
HWNDhW,hPW;
MSGms;

wc.lpszClassName="goo";
wc.lpfnWndProc=(WNDPROC)WinProcedure;
wc.hInstance=hI;
wc.style=CS_HREDRAW|CS_VREDRAW;
wc.cbClsExtra=NULL;
wc.cbWndExtra=NULL;
wc.hIcon=LoadIcon(NULL,IDI_EXCLAMATION);
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName=NULL;
RegisterClass(&wc);
hW=CreateWindow
(
"goo",
"教えて!goo",
WS_OVERLAPPED,
0,
0,
640,
456,
NULL,
NULL,
hI,
NULL
);
ShowWindow(hW,nCS);
UpdateWindow(hW);
while(GetMessage(&ms,NULL,NULL,NULL))
{
TranslateMessage(&ms);
DispatchMessage(&ms);
}
return (ms.wParam);
}

もっと簡単にDosWindowが開かないようにする方法はないのでしょうか?
もしないとすると上記記述でもっと簡単にできないでしょうか?

わざわざWindowsアプリにして以下のようにするしかないのでしょうか?

LONG WINAPI WinProcedure(HWND hW,UINT wM,UINT wP,LONG lP)
{
//ここに宣言を置く
switch(wM)
{
case WM_CREATE:
//ここに処理を置く
return 0;
default:
return(DefWindowProc(hW,wM,wP,lP));
}
}
WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int nCS)
{
WNDCLASSwc;
HWNDhW,hPW;
MSGms;

wc.lpszClassName="goo";
wc.lpfnWndProc=(WNDPROC)WinProcedure;
wc.hInstance=hI;
wc.style=CS_HREDRAW|CS_VREDRAW;
wc...続きを読む

Aベストアンサー

ウィンドウを開く必要がないなら、mainをWinMainに変更するだけで良いのでは? ウィンドウクラス登録、ウィンドウ作成、メッセージループ、ウィンドウプロシージャは全て不要な気がしますが。

WINAPI WinMain(HINSTANCE hI,HINSTANCE,LPSTR,int nCS)
{
  //処理内容

  return 0;
}

Q{x = x>y ? x:y; return x;}

#include <iostream>
using namespace std;

inline int max(int x, int y){x = x>y ? x:y; return x;}

int main()
{
int num1, num2, ans;

cout << "2つの整数を入力して。\n";
cin >> num1 >> num2;

ans = max(num1, num2);

cout << "最大値は" << ans << "です。\n";

return 0;
}
の{x = x>y ? x:y; return x;}の部分の意味が解りません。

Aベストアンサー

inline int max(int x, int y){x = x>y ? x:y; return x;}
これを普通に関数で書くと

int max(int x, int y)
{
x = x>y ? x:y;
return x;
}

です。

x = 部分は右辺の結果が代入されます。これはわかりますよね。
x>y?x:y;
と書くと?より左にある条件式を判定し、その結果が真である場合は:で区切られた左側の値を、偽である場合は右の値を帰します。
x>yが真であればxを、偽であればyを返します。
それが、左辺値xに代入され、関数の戻り値として帰ります。

従って、2つの値をこの関数に入れると、大きいほうの値が帰ることになります。

QC言語のプログラムで#includeを使わず#includeだけで

C言語のプログラムで#include<math.h>を使わず#include<stdio.h>だけで√(sqrt)を表現することは可能でしょうか?

Aベストアンサー

ご自分で sqrt 関数を作れば可能です。
こんな感じでしょうか。

#include <stdio.h>

static double
sqrt (double s)
{
 double x = s / 2.0;
 double last_x = 0.0;

 while (x != last_x)
 {
  last_x = x;
  x = (x + s / x) / 2.0;
 }

 return (x);
}

int
main (int argc, char * argv[])
{
 printf ("sqrt (%f) = %f\n", 3.0, sqrt (3.0));
}

Qint main()、void main()、void main(void)、int main(void)

今日、大学でC言語の講義の時間、先生が、

#include <stdio.h>

void main(void){

}

と宣言してプログラムを書くと教えていました。
main関数には、
main()
void main()
void main( void )
int main()
int main( void )

と、人によりいくつかの描き方があったりします。
どれが本当は正しいのでしょうか?
void mainはすべきではないとなんかの本で読んだのですが・・。

Aベストアンサー

通称C89という以前の言語規格(現行コンパイラの多くが準拠)では、下記のいずれかが正しい。
int main(int argc, char *argv[])
int main(void)

但し、最新のC言語規格(通称C99)では、
<ISO/IEC9899:1999>
or in some other implementation-defined manner.
</ISO/IEC9899:1999>
となっているので、処理系が戻り値のvoidを認めていればvoidも可。
# 組込み系などで戻り値を使わない環境もあるためでしょうか。

なので、コンパイラのマニュアルで戻り値のvoidにしていい/しろと書いてない限り、
voidは言語仕様的には正しくない。(でも動くものもある)

Qchar AA[]{"全角文字"};から"全"という一字を取り出したい

 今晩は、Cの初心者です、宜しくお願いします。
 全角文字の入ったchar AA[]{"全角文字"};から"全"という文字一字を取り出す時にAA[0]とかくとエラーになります。
 どのようにしたら取り出せるのでしょう。
 ポインタを使う方法と使わない方法を教えて下さい。
 宜しくお願いします。

Aベストアンサー

お疲れ様です。

まずお伺いしたのがOSおよび開発するためのコンパイラです。

ロケール等の話は分かりませんが、昔のC言語で日本語を扱う場合には全角文字1文字で2個つのchar領域を使用していました。
(マルチバイト文字セットと言います。)

詳細は参考URLを参照の事。

windowsでVCと仮定した場合、charを使われていると言うことは、多分、shift-jis(シフトJIS)で文字列を扱っていると思われます。

結論として全角文字1文字だけを取り出したいという場合は、結局char2個分のデータを取り出す必要があります。

>char AA[]={'全','角'};

char AA[]="全角";
とし
>printf("%s%s\n" , AA[0],AA[1] ) ;

printf("%c%c\n" , AA[0],AA[1] ) ;
とすれば、「全」だけを表示する事が可能と思われます。

日本語を文字列で表示する為の文字コードについては
Shift-JISだけでなく、UnicodeやUTF・EUC・JISなどがあります。

もう少し詳しく記載してあるホームページはないか探してみましたが、ちょっと無理でした。

参考URL:http://marupeke296.com/CPP_charUnicodeWideChar.html

お疲れ様です。

まずお伺いしたのがOSおよび開発するためのコンパイラです。

ロケール等の話は分かりませんが、昔のC言語で日本語を扱う場合には全角文字1文字で2個つのchar領域を使用していました。
(マルチバイト文字セットと言います。)

詳細は参考URLを参照の事。

windowsでVCと仮定した場合、charを使われていると言うことは、多分、shift-jis(シフトJIS)で文字列を扱っていると思われます。

結論として全角文字1文字だけを取り出したいという場合は、結局char2個分のデータを取り出...続きを読む


人気Q&Aランキング

おすすめ情報