Причиной симптомов вы описываете, что вы смешиваете форматированный ввод с getline
. Существует также фундаментальная проблема , что вы никогда не проверяете, успешно ли какой-либо вход.
Реальная проблема проявляется после inps >> data
строк: эти строки пропустить пробелы и не читать int
и не больше. В частности, они оставляют любые конечные пробелы, , включая символ '\n'
, в потоке. Так что в вашем второго случая ввода, после прочтения 22
, есть еще '\n'
в потоке, который завершит следующий вызов getline
(который вместо чтения " Ricky"
, будет читать ""
). Это приводит к тому, что вход становится несинхронизированным, что в в ближайшее время приводит к вашему inps >> data
, когда поток , расположенный в "Rahul"
. Попытка прочитать int
при вводе "Rahul"
не удалась, и отказ был липким; он останется , пока вы его не сбросите, а все дальнейшие попытки не будут выполняться. Начиная с вы уже что-то читали в line
, он никогда не станет , и вы будете навеки, ничего не делая.
Первое, и самое важное изменение, чтобы проверить после каждый вход, вход преуспела, а не пытаться читать дальше, если это не имеет. (Структура вашего файла такова, что вы, , вероятно, не можете надежно повторно синхронизировать, если есть ошибка. В противном случае рекомендуется провести повторную синхронизацию, а продолжить, чтобы вы могли уловить несколько ошибок ввода ,)
Второе, что вам нужно сделать, это убедиться, что при вводе целых чисел вы читаете полную строку (включая '\n'
). Существует два способа сделать это: классический способ - использовать getline
, затем инициализировать std::istringstream
с помощью линии и ввести int
, используя это. (Это позволяет дополнительные проверки ошибки, например, что не существует никакого дополнительного мусора в линии.) В качестве альтернативы, можно назвать inps.ignore( std::numeric_limits<std::streamsize>::max(), '\n');
, который будет извлекать и не игнорировать символы до '\n'
(который также экстрагируют).
EDIT:
На перечитывать, это происходит со мной, что мой текст описания не все , что понятно, так вот что происходит в ступенчатом explination:
Первый раз через петлю все работает так, как ожидалось, , но входное положение сразу за "22"
(который был последним входом ).
Вызывается getline
в верхней части цикла. Он будет вернуть все символы между "22"
и концом этой линией. Если за "22"
сразу следует новая строка, это приведет к пустой строке, завершающей цикл (хотя еще есть данные для чтения). Если есть дополнительных символов после "22"
(скажем, пустой или около того), то они будут считаться строкой.
Предполагая, что были дополнительные символы, то вы читали «Рики», как имя отца, и сделать inps >> data
для числа рулона на струне "Rahul"
. Это не работает, и задает поток в состоянии ошибки, что приводит к тому, что все операции будут нерабочими.
Так что, когда вы в следующий раз достичь вершины цикла, getline
является не-оп, предыдущее содержимое line
не изменились, и вы снова войти в петлю. И снова, и снова, потому что до тех пор, пока вы не очистите ошибку, все операции будут неработы. Все переменные сохраняют свои старые значения.
Самое простое решение, вероятно, что предложил Нил Кирк в комментарий: прочитать весь файл в станд :: вектор строк, и анализировать те:
class Line
{
std::string myContents;
public
friend std::istream& operator>>(std::istream& source, Line& obj)
{
std::getline(source, obj.myContents);
return source;
}
operator std::string() const { return myContents; }
};
// ...
std::vector<Line> lines((std::istream_iterator<Line>(inps)),
(std::istream_iterator<Line>()));
Если вы хотите прочитать файл на лету, однако (скажем, потому что может быть слишком большой, чтобы поместиться в памяти, или просто потому, что это хорошее обучение упражнения):
while (std::getline(inps, line) && !line.empty()) {
// but do you really what the second condition.
// if so, you should probably provide
// a function which will ignore whitespace.
s1.setName(line);
if (std::getline(inps, line)) {
s1.setFatherName(line);
}
if (std::getline(inps, line)) {
std::istringstream s(line);
int data;
if (s >> data) {
s1.setRollNo(data);
}
}
if (std::getline(inps, line)) {
std::istringstream s(line);
int data;
if (s >> data) {
s1.setAge(data);
}
}
}
Это очень красноречиво.По-прежнему требуется дополнительная ошибка , и вы, вероятно, захотите отслеживать номер строки , чтобы вы могли выводить ее с любым сообщением об ошибке. Но это shoul указывает вам в правильном направлении.
EDIT2:
Кроме того, вы не хотите, чтобы открыть выходной файл каждый раз через петля. Попытка открыть уже открытый std::ofstream
завершится с ошибкой, как указано выше, после того, как поток потерпел неудачу, все попытки использовать его не будут.
В этом случае цикл while будет иметь больший смысл. – Borgleader
Я пробовал это, но такую же проблему –
y u no indent ваш код – rightfold