Чтение целых чисел из cin до тех пор, пока не будет нажата клавиша ESC С++

Меня интересует решение следующей проблемы:

Я должен читать целые числа из CIN, пока пользователь не нажмет ESC и не вычислит среднее значение положительных и четных целых чисел.

Моя проблема в том, что я не совсем уверен, как правильно написать условие остановки.

Вот что я пробовал до сих пор (не работает должным образом)

#include<iostream>
#include<math.h>

using namespace std;

void main()
{
    int c, sum=0, i=0;
cout<<"Insert characters: ";
while(cin>>c)
{
    i++;
    if((int)c>=0&&(int)c%2==0){
        sum+=(int)c;
    }
}
cout<<"Average: "<<(float)sum/i<<endl;
system("pause");
}

person Adrian Olar    schedule 24.11.2013    source источник
comment
Я не знаю, как проверить клавишу escape, но вам нужно переместить i++ внутрь условия if(), иначе вы будете считать все четные и нечетные целые числа.   -  person Brady    schedule 24.11.2013
comment
Вы читаете цифры, но ESC - это не цифра, а управляющий код. Я думаю, что даже через оператора ›› его не пропустят. Вы должны использовать какую-то низкоуровневую функцию чтения консоли для доступа к специальным нажатиям клавиш.   -  person mcleod_ideafix    schedule 24.11.2013
comment
Брэди, это правильно насчет i++, но я все еще застрял на условии выхода...   -  person Adrian Olar    schedule 24.11.2013
comment
Кроме того, что, если кто-то нажмет букву вместо цифры? Почему условие выхода должно быть ESC? Почему бы не сделать это «q» или что-то столь же простое?   -  person Brady    schedule 24.11.2013
comment
это требование....:) было бы легко поставить условие остановки на простой символ...   -  person Adrian Olar    schedule 24.11.2013


Ответы (2)


Экранирующий символ не является ни цифрой, ни пробелом. Таким образом, если программе передается символ в потоке, вы можете просто читать целые числа, и поток автоматически завершится ошибкой при вводе символов espace (просто сосредоточившись на входном аспекте вопроса):

#include<iostream>

int main()
{
    int c = 0;
    while (std::cin >> c) {
        std::cout << "c=" << c << '\n';
    }
}

Однако пересылаются ли escape-символы в поток операционной системой — это другой вопрос. Например, в UNIX-системах escape-символ будет переадресован, но только тогда, когда программа получает ввод, что по умолчанию происходит при вводе строки. Если программа не должна ждать ключа возврата, операционная система должна получить указание не ждать ключа возврата.

Вопрос, кажется, для Windows, но я недостаточно знаю о Windows, чтобы определить, как изменить там настройки терминала (хотя см. ниже что-то, что все еще может работать). В UNIX вы должны снять флаг ICANON в настройках терминала, используя tcgetattr() и tcsetattr(). Например, вы можете использовать это:

#include <iostream>
#include <termios.h>

int main()
{
    termios values;
    tcgetattr(0, &values);
    values.c_lflag &= ~ICANON;
    tcsetattr(0, TCSANOW, &values);

    int c = 0;
    while (std::cin >> c) {
        std::cout << "c=" << c << '\n';
    }
}

Я думаю, что в Windows есть getch(), которые дают вам один символ без ожидания. Это, надеюсь, также включает в себя escape-символ. Если это так, вы можете просто создать простой буфер потока вокруг getch() и использовать его вместо этого:

#include <iostream>
#include <streambuf>
#include <whatever-declares-getch>

struct getchbuf
    : std::streambuf {
    static int const end = <getch()-error-value-goes-here>;
    char buffer;
    int underflow() {
        int result(traits_type::eof());
        if (this->gptr() == this->egptr() && (result = getch()) != end) {
            buffer = traits_type::to_char_type(result);
            this->setg(&buffer, &buffer, &buffer + 1);
        }
        return result;
    }
};

int main()
{
    getchbuf sbuf;
    std::istream in(&sbuf);

    int c = 0;
    while (in >> c) {
        std::cout << "c=" << c << '\n';
    }
}

Вам нужно исправить приведенный выше код, чтобы включить все, что объявляет getch() (я думаю, что это <conio.h>, но я не знаю), и указать индикатор ошибки getch().

person Dietmar Kühl    schedule 24.11.2013
comment
Спасибо за ваши предложения! - person Adrian Olar; 28.11.2013

Вы можете попробовать это

while((ch = cin.get()) != 27)
{
  i++;
  if((int)ch>=0&&(int)ch%2==0
  {
    sum+=(int)ch;
  }
}

Это должно повторяться до тех пор, пока не будет нажата клавиша esc

person David Pilkington    schedule 24.11.2013
comment
к сожалению не работает... консоль застряла на чтении, не останавливается... - person Adrian Olar; 24.11.2013
comment
@AdrianOlar Вы имеете в виду, что условие while никогда не бывает ложным? - person David Pilkington; 24.11.2013
comment
Это будет работать только в том случае, если пользователь вводит символ, значение ASCII которого равно 27. - person 0x499602D2; 24.11.2013
comment
@0x499602D2, а значение ASCII ключа esc равно 27 robelle.com/smugbook/ascii.html< /а> - person David Pilkington; 24.11.2013
comment
Чтобы это работало, нужно отключить буферизацию строк на cin. - person Pat; 24.11.2013
comment
да, условие while никогда не бывает ложным. По крайней мере, это то, что я могу наблюдать из вывода в моей консоли... - person Adrian Olar; 24.11.2013
comment
@Pat Как это сделать? - person 0x499602D2; 24.11.2013
comment
@ 0x499602D2: это зависит от платформы. В posix-системе вам понадобятся функции termios (см. справочные страницы). В Windows я не уверен, но вам, вероятно, будет лучше напрямую использовать функции консоли winapi. - person Pat; 24.11.2013
comment
я проверил ваш код, и это просто очищает содержимое строки, когда я нажимаю кнопку ESC, и это никогда не прекращает прослушивание ввода... - person Adrian Olar; 24.11.2013