1

反復ごとに変数の値をインクリメントするループを実行しています。キーボードのキーを押してループを停止し、変数の最終値を報告できるようにしたいと考えています。Cでこれを行う方法がわかりません。これを行うための本当にシンプルで簡単な方法を見落としているように見えるので、愚かだと感じますが、キーを押すまでループを停止しようとします。キーボードは、本質的に私が望むものとは正反対です。

基本的に私がやりたいことは次のようなものです:

 
   while (key is not pressed)
increment value
print final value

それは理にかなっていますか?とにかく、Cでこれを行う方法に関するヒントはありますか?

4

10 に答える 10

7

Linux の端末から (Enter キーを押さずに) 1 文字ずつ読み取ろうとする場合は、端末を非バッファ入力用に設定する必要があります。

次の例を参照してください。

GNU/Linux での非バッファー getc(3)

于 2009-07-31T23:36:36.387 に答える
2

Windows で作業していて、MSVC を使用している場合、getch() と kbhit() が必要になる場合があります。

#include <conio.h>

while( looping ) {

    // do regular loop stuff

    // check if a key is hit, w/o blocking, using kbhit()
    if( kbhit() ) {
        // only runs when user has hit a key
        // so display stuff here,
        // and wait for permission to resume with getch()
        getch();
    }
}
于 2009-07-31T23:39:06.787 に答える
2

何を押すかを指定することが許可されていて、POSIX.1 準拠のシステムを使用している場合は、SIGINT (Ctrl+C で送信) をキャッチするシグナル ハンドラーを設定できます。while ループから抜けるように、ハンドラーに変数の値を変更させます。

このアプローチを選択する場合は、注意してください。不適切な実装によって無限ループが発生し、SIGINT がキャッチされた場合、Ctrl+C を使用してプログラムを終了することはできません。この場合、プログラムを終了するには kill(1) を使用する必要があります。

于 2009-07-31T23:44:47.667 に答える
1

プラットフォームによって異なります。C 言語は、このようなものを定義しません。

ウィンドウズ?Linux?(gnome アプリ? kde アプリ? ターミナル?) 何か他のもの?

于 2009-07-31T23:30:48.410 に答える
1

これは、C 標準がプログラマーを干からびさせる場所の 1 つです。この問題に対する最も移植性の高い解決策はcursesライブラリを使用して I/O を実行することです。このライブラリは、いわゆる「生の」キーボード入力 (これが必要です) に加えて、さらに多くの機能を処理します。学習曲線は少し急ですが、特に BSD プログラマーのドキュメントには優れたチュートリアルがあります。

于 2009-08-01T02:02:01.043 に答える
0

私はあなたが尋ねている逐語的な質問ではなく、あなたの意図に目を向けようとします-どうやらあなたは何らかのユーザーの反応によって引き起こされた計算の結果を提示したいと思っています。

「キーが押されていますか?」すべての反復でかなり無駄があります。CPUは、より有用なことを行うためにそのすべての時間を費やす可能性があります。

したがって、ここでの最善のアプローチは、私の意見では、シグナルを使用することです。つまり、「Ctrl-C」を押すとトリガーされるSIGINTです。Ctrl-Cを押すと変数の値を出力し、3回押すと終了するコードを次に示します。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

long globalvar = 0;
int interrupts_before_exit = 3;

void ctrl_c_handler(int x) {
  printf("Value of the variable: %ld\n", globalvar);
  if(--interrupts_before_exit) {
    printf("Press Ctrl-C %d more times to stop\n", interrupts_before_exit);
  } else {
    printf("Computation interrupted!\n");
    exit(0);
  }
}


int main(int argc, char *argv[]) {
  struct sigaction act;

  act.sa_handler = ctrl_c_handler;
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;

  if(sigaction(SIGINT, &act, NULL) >= 0) {
    while (1) {
      /* The work happens here */
      globalvar++; 
    }
  }
  exit(1);
}

プログラム間で信号を渡すことができるので、実際には「作業」を行うプログラムをフォークすることができ、2番目のプログラムはキーボードを怠惰に監視します-そしてそこでキーが押されるとすぐに信号を結果を出力する最初のもの。

于 2009-08-01T13:04:24.933 に答える
0

システムとその動作方法によっては、STDIN をファイル ハンドルとして select 関数を使用することができます。Select ステートメントの時間をゼロに設定して、ポーリングしてデータがあるかどうかを確認したり、待機する時間を設定したりできます。

あなたはリンクを見ることができますhttp://www.gnu.org/s/libc/manual/html_node/Waiting-for-I_002fO.htmlを参照して、ソケットで select ステートメントを使用する例を確認してください。

この例を変更して、STDIN をファイル記述子として使用するようにしました。この関数は、保留中の入力がない場合は 0 を返し、保留中の入力がある場合 (つまり、誰かが入力のキーボードでキーを押した場合) は 1 を返し、何らかのエラーが発生した場合は -1 を返します。

 #include <errno.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/time.h>

 int waitForKBInput(unsigned int seconds)
 {
   /* File descriptor set on which to wait */
   fd_set set;
   /* time structure which indicate the amount of time to
      wait.  0 will perform a poll */
   struct timeval timeout;

   /* Initialize the file descriptor set. */
   FD_ZERO (&set);
   /* Use the Standard Input as the descriptor on which 
      to wait */
   FD_SET (STDIN, &set);

   /* Initialize the timeout data structure. */
   timeout.tv_sec = seconds;
   timeout.tv_usec = 0;

   /* select returns 0 if timeout, 1 if input available, -1 if error. */
   /* and is only waiting on the input selection */
   return select (FD_SETSIZE,
                  &set, NULL, NULL,
                  &timeout));
 }

これを試してみたところ、SelectとSTDINの実装が異なるため、機能しませんでした(キーボード入力を検出するために他の手段を使用する必要がありました)。

Visual C/C++ の場合、読み取るキーボード入力があるかどうかを示す関数 kbhit を使用できます。

于 2009-08-01T03:08:10.290 に答える
0

文字を読み取るために呼び出している関数がブロックされています。そこに文字がない場合は、代わりに返す必要があります。

ここでの魔法の検索用語は、非ブロッキングおよび非バッファリング入力です。

于 2009-07-31T23:31:11.140 に答える
0

誰かがキーを押すまでループでカウントするのはなぜ意味があるのでしょうか?

1万回の反復のタイミングをチェックするよりも、本当に何かが必要な場合。次に、sleep() を使用して非ブロッキング イテレーションで待機させます。時間を取得したら、それを使用して「最終値」を概算できます

于 2009-07-31T23:34:51.303 に答える