Понимание cin.fail () и cin.clear - Vector Appending Program - PullRequest
2 голосов
/ 06 января 2020

Это мой первый пост в Stack Overflow, пожалуйста, прости меня, если я пропустил какие-либо формальности в следующем посте

В настоящее время я пишу программу на C ++ для Code :: Blocks 17.12, используя GNU G CC Компилятор. Программа предназначена для Упражнения P6.4 Big C ++ 2nd Edition, где я должен написать функцию для добавления / объединения двух векторов, введенных пользователем, а затем возврата вектора

Я могу ввести 1-й вектор просто отлично , но по какой-то причине он не позволяет мне ввести 2-й вектор.

У меня такое ощущение, что использование cin.fail () в то время как l oop также вызывает мое значение 2-го bool немедленно изменить на ложное. Для этого я добавил cin.clear (), надеясь, что он сбросит поток для учета 2-го векторного ввода, но безрезультатно.

Действительно ли cin.fail () вызывает эту ошибку или нет что-то еще я пропускаю?

Редактировать: с помощью crtl-z я теперь могу получить 2-й вектор и запустить программу до конца, хотя последний элемент первого вектора a / a_vct копирует дважды. Можете ли вы указать мне некоторые ресурсы по использованию crtl-z, чтобы лучше понять его использование? (еще не освещал это в книге) если я введу 1 2 3 для a_vct и 1 2 3 для b_vct, c_vct выведет 1 2 3 3 1 2 3 0

#include <iostream>
#include <vector>
using namespace std;

vector<double>append(vector<double>a,vector<double>b)
{
    vector<double>c; //combined vct

    for (int i=0; i<a.size(); i++)
    {
        c.push_back(a[i]);
    }

    for (int i=0; i<b.size(); i++)
    {
        c.push_back(b[i]);
    }

    return c;
};

int main()
{
    vector<double>a_vct; //inputs
    vector<double>b_vct; //inputs
    vector<double>c_vct; //appended vct

    cout<<"Welcome to the vector append-er!"<<endl;

    cout<<"Please enter 1st Vector (enter v to set vector after inputs):"<<endl;
    bool v1_add=true;
    while(v1_add)
    {
        double a;

        cin>>a;
        a_vct.push_back(a);

        if(cin.fail()) //double usage is setting both bools to false???
        {
            v1_add=false;
        }
    }

    cin.clear();

    cout<<"Please enter 2nd Vector. Please enter the same number of elements (enter v to set vector after inputs):"<<endl;
    bool v2_add=true;
    while(v2_add)
    {
        double b;

        cin>>b;
        b_vct.push_back(b);

        if(cin.fail())
        {
            v2_add=false;
        }
    }

    c_vct=append(a_vct,b_vct);

    cout<<"The appended vector is:"<<endl;
    for (int i=0; i<c_vct.size(); i++)
    {
        cout<<c_vct[i]<<" ";
    }


    return 0;
}

Редактировать 2: Новые изменения в соответствии с ответом, работают как задумано сейчас

if(cin.good())
        {
            a_vct.push_back(a);
        }
if(cin.good())
        {
            b_vct.push_back(b);
        }

Ответы [ 2 ]

4 голосов
/ 06 января 2020

После ввода первых векторных входов напишите Ctrl+Z (с помощью клавиатуры вместо числа) для windows или Ctrl+D для linux, чтобы cin.fail() было true, чтобы остановить l oop брать входы и после ввода вторых векторных входов тоже.

Обратите внимание, что векторы будут повторять последние записи, потому что вы делаете push_back(a) после обнаружения cin.fail(). Таким образом, вы можете избежать этого, изменив

a_vct.push_back(a);

на

if(cin.good()) a_vct.push_back(a);

2 голосов
/ 06 января 2020

Выбранный ответ решает непосредственную проблему, но ...

Если у вас есть сбойный ввод, вам не только нужно очистить флаг сбоя, вы также можете удалить неправильный ввод. Если вы этого не сделаете, при следующем чтении попытается проанализировать тот же неверный ввод и снова потерпит неудачу. Удаление неверного ввода часто выполняется с помощью std::istream::ignore. Типичное использование

cin.ignore(numeric_limits<streamsize>::max(), '\n')

удаляет все в потоке до конца строки. Вы можете заменить '\n' пробелом, табуляцией, запятой или любым другим символом, который лучше соответствует вашим требованиям. Будьте абсолютно уверены, что у вас неверный ввод, а не какой-либо другой случай сбоя, или вы можете обнаружить, что удаляете нужные вам данные.

Sidenote:

 cin>>b;
 b_vct.push_back(b);
 if(cin.fail())
 {
     v2_add=false;
 }

- плохая идея. Если cin>>b; не удалось, вы не хотите добавлять b к vector. Вы должны убедиться, что b хорош, прежде чем добавить его.

 cin>>b;
 if(cin.fail())
 {
     v2_add=false;
 }
 else
 {
     b_vct.push_back(b);
 }

Но мы можем воспользоваться возвращаемым значением cin >>b; и немного переставить logi c, чтобы сделать это проще:

 if(cin>>b) // if read succeeded
 {
     b_vct.push_back(b); // store
 }
 else
 {
     v2_add=false; // read failed
 }

Тогда, если мы примем while во внимание

while(v2_add) // loop until failed
{
    if(cin>>b)
    {
        b_vct.push_back(b);
    }
    else
    {
        v2_add=false;
    }
}

Мы видим, что if нам вообще не нужен. Он выполняет работу, которая может быть выполнена в состоянии while.

while(cin>>b) // loop until read fails
{
    b_vct.push_back(b); // store
}

И поскольку единственным выходом из l oop является сбой, это место, где вы размещаете clear и, возможно, ignore

while(cin>>b) // loop until read fails
{
    b_vct.push_back(b); // store
}
// Check for EOF here if appropriate
cin.clear(); // clear error flag
// discard invalid input if appropriate
// cin.ignore(numeric_limits<streamsize>::max(), '\n'); // discard up to end of line

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

cin.clear(); // clear error flag
std::string discard;
cin >> discard; // discard whatever follows
...