Re[3]: Проверка данных при вводе. Нужна помощь!
От: LaptevVV Россия  
Дата: 25.12.06 07:03
Оценка:
Здравствуйте, maksqwe, Вы писали:

I>>В некоторых случаях можно так:


I>>
I>>#include <iostream>
I>>using namespace std;
I>>int main()
I>>{
I>>    int i;
I>>    if (cin >> i)
I>>        cout << "i = " << i << '\n';
I>>    else
I>>        cout << "error\n";
I>>}
I>>


M>После чего бесконечно повторяется следующая функция... Как сделать что бы этого не происходило???

вот так — читай сюда:

Состояния потока
Каждый поток (и стандартные в том числе) в каждый момент времени находится в некотором состоянии. Эти состояния имеют названия good, bad, fail и eof (end-of-file). Сами состояния определены в классе ios_base как целые статические константы. Эти константы называют флагами состояния потока [1-27.4.2.1.3].

typedef int iostate;
goodbit     = 0x00   
badbit      = 0x01 
eofbit      = 0x02
failbit     = 0x04

Значения флагов зависят от реализации (показанные значения флагам присвоены в системе C++ Builder 6), однако имена определены в стандарте, поэтому именно так флаги состояния называются во всех без исключения системах. В программе имена флагов состояния нужно записывать с префиксом, например
std::ios_base::eofbit

С таким же успехом можно использовать класс, производный от ios_base. В частности, в текстах программ стандартной библиотеки часто встречается более короткий префикс
std::ios::eofbit

В базовом классе ios_base определено поле
iostate _M_iostate;            // библиотека STLport

ПРИМЕЧАНИЕ
Такое имя поле имеет в системе Borland C++ Builder 6. В другой реализации имя поля может быть другим.
В этом поле сохраняются флаги состояния во время работы программы. Это поле мы можем прочитать методом
iostate rdstate();

Установить любой флаг можно методом
void setstate(iostate flag);

Для установки нескольких флагов, естественно, нужно воспользоваться битовыми операциями, например
setstate(std::ios::eofbit | std::ios::failbit);

Система ввода/вывода С++ предоставляет несколько методов, с помощью которых мы всегда можем узнать состояние потока:
bool good() const;    // следующая операция может выполняться
bool eof() const;    // виден конец ввода
bool fail() const;    // следующая операция не выполняется
bool bad() const;    // поток испорчен

Если после выполнения некоторой операции поток находится в состоянии good, то это хорошая ситуация: во время предыдущей операции не произошло никаких непредвиденных событий и может быть выполнена следующая операции ввода/вывода. В остальных случаях следующая операция выполнена не будет.
Состояние fail и состояние bad являются состояниями ошибки потока. Если поток находится в одном из этих состояний, то операции обмена не выполняются. Состояние bad включает в себя состояние fail: когда поток находится в состоянии bad, он находится и в состоянии fail; обратное неверно.
Если поток находится в состоянии fail, то операция ввода/вывода завершилась неудачно, однако поток не испорчен и никакие символы не потеряны. Обычно это состояние устанавливается при ошибках форматирования в процессе чтения — например, программа пытается прочитать целое число, а первый же символ является недопустимым (буква или знак операции). Поток из состояния fail мы можем вернуть в нормальное состояние с помощью метода clear(), например
if (stream.fail()) stream.clear();

После этого можно выполнять операции обмена — опять до очередной ошибки. Метод clear() перегружен и позволяет не только сбросить, но и затем установить нужные флаги состояния. Прототип этого метода
void clear(iostate flag);

Состояние bad – это более тяжелое состояние. Флаг badbit указывает на неработоспособность потока данных или потерю данных. Когда поток в состоянии bad, ни в чем нельзя быть уверенным, поэтому в таких случаях лучше завершать выполнение программы.
Состояние eof может возникнуть только при операции чтения. Для стандартного потока ввода это состояние возникает при вводе комбинации клавиш <Ctrl> + <z>. Для файлов это состояние устанавливается при первой попытке чтения после последнего байта файла. При этом поток тоже переводится в состояние fail.
Состояние потока и логические условия
Состояние потока можно проверять непосредственно в условиях if и while. Например, ввод массива целых значений можно выполнять в цикле таким образом
int aa[10] = {0};
i = 0;
while(cin >> aa[i++]);

Цикл завершается по одной из двух причин:
1. Создалась ситуация «end-of-file»; для входного потока это эквивалентно нажатию комбинации клавиш <Ctrl> + <z>;
2. В потоке встретился символ, не соответствующий типу вводимой переменной; в этом случае поток переводится в состояние fail;
Например, мы набрали на клавиатуре следующую последовательность символов
1<пробел>2<пробел>3<пробел>4<пробел>5e6<enter>
Тогда элементы массива а будут иметь следующие значения:
aa[0] = 1;
aa[1] = 2;
aa[2] = 3;
aa[3] = 4;
aa[4] = 5;
aa[5] = 0;
aa[6] = 0;
aa[7] = 0;
aa[8] = 0;
aa[9] = 0;

Символ ‘e’после цифры 5 не является допустимым для целого числа, поэтому ограничивает ввод.
В условиях можно задавать и явный вызов методов. Например, мы хотим посчитать количество символов ‘\n’, которым оканчиваются вводимые строки. Это можно сделать, используя метод get():
int nl = 0;
while(cin.get(ch))             // читать все символы, в том числе пробельные
{ if(ch=='\n') nl++; 
  cout.put(ch); 
}

Так как «неправильных» символов не существует, цикл можно завершить только вводом комбинации <Ctrl> + <z>. Можно использовать и другую форму метода get():
int nl = 0;
while(ch = cin.get() && ch != EOF)             // читать все символы
{ if(ch=='\n') nl++; 
  cout.put(ch); 
}

Константа EOF помещается в ch при нажатии комбинации <Ctrl> + <z>.
В библиотеке реализована логическая операция operator!, с помощью которой можно проверить аварийное состояние потока, например
if (!(cin >> x))
{    // ввод завершился неудачей
    . . .
}

Обратите внимание, выражение ввода заключено в скобки. Это делать необходимо, так как в соответствии с приоритетом операций выражение без скобок интерпретируется как
(!cin) >> x

Естественно, ввод и проверку состояния потока можно разделить, например
cin >> x;
if(!cin)
{    // ввод завершился неудачей
    . . .
}

Во всех приведенных примерах, на месте cin может стоять любой поток.
При разделении ввода и проверки можно использовать явный вызов соответствующего метода. Например, таким способом мы можем проверять наступление ситуации «end-of-file» для потока, связанного с файлом.
while (!from.eof())         // явная проверка на конец файла
{ getline(from, s);         // чтение строки из потока from
  cout << s << endl; 
}

Однако тут возможны сюрпризы. По умолчанию ограничителем строки является символ ‘\n’, который записан в конце каждой строки. В данном случае при считывании последней строки ситуации конца файла не возникает — она возникает только при попытке ввода за концом файла. Поэтому цикл выполнится лишний раз и на экране дважды появится последняя строка.
Правильная последовательность операторов может быть такой
getline(from, s);             // чтение строки из потока from
while (!from.eof())         // явная проверка на конец файла
{ cout << s << endl; 
  getline(from, s);         // чтение строки из потока from
}

Другой вариант — бесконечный цикл с проверкой «end-of-file» внутри цикла
while (true)         
{   getline(from, s);         // чтение строки из потока from
    if(from.eof()) break;     // явная проверка на конец файла
    cout << s << endl; 
}

Хочешь быть счастливым — будь им!
Без булдырабыз!!!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.