2016-02-13 8 views
0

Я изучаю C++ и задаю несколько вопросов.C++: Устранение неполадок while с вложенным оператором if/else

Эта программа должна принимать входные данные для имени и цены элементов и выводить их в текстовый файл. Когда для имени элемента вводится значение 999 сторожевого знака, цикл while должен прекратить и выводить все текстовые файлы в виде всех входов (название и цена).

У меня есть две проблемы с этой программой:

  1. Только самый последний набор входов (наименование, цена) отображается. Как сохранить все входы в память?

  2. Ввод 999 для названия элемента не приводит к выходу программы. Вместо этого программа перестает отображать подсказки. Как я могу остановить программу правильно?

Возможно, я должен использовать цикл for, но я не уверен, как это будет реализовано.

#include <iostream> 
#include <string> 
#include <fstream> 

using namespace std; 

int main() 
{ 
    string item_name; 
    double price; 
    int item_number; 

    const string SENTINEL = "999"; 

    ofstream myfile ("invoice1.txt"); 


    while(item_name != SENTINEL) 
    { 
     cout<<"Enter the name of the item."<<'\n'; 
     cin>>item_name; 

     if (item_name == SENTINEL) 
     { 
      cin>>item_name; 
      myfile<<"Thank you for your entries"<<'\n'; 
      myfile<<item_name<<"#"<<price<<endl; 
      myfile.close(); 

      break; 
     } 
     else 
     { 
      cout<<"Enter the price of the item."<<'\n'; 
      cin>>price; 
     } 
    } 

    myfile<<"Thank you for your entries"<<'\n'; 
    myfile<<item_name<<"#"<<price<<endl; 
    myfile.close(); 

    return 0; 
} 
+2

Компилятор может не заботиться о форматировании в виде пробелов, но люди делают это. Пожалуйста, правильно отложите свой код в будущем. –

ответ

0

Как это сделать с std::vector

Во-первых, некоторые из них включает в себя:

#include <vector> // obviously. Can't do vectors without the vector header. 
#include <limits> // for a trick I'll use later 

Создать структуру, чтобы связать имя элемента с a)

struct item 
{ 
    string name; 
    double price; 
}; 

и сделать вектор этой структуры

vector<item> items; 

Тогда после того, как вы читаете в названии и цене, вещи его в структуре и набивать структуру в вектор.

item temp; 
temp.name = item_name; 
temp.price = price; 
items.push_back(temp); 

О том, почему петля while не работает ... Это пройдется до конца.

while(item_name != SENTINEL) 

Это хорошее начало. Если item_name не SENTINEL, продолжайте движение. Абсолютно верно. Дело в том, что имя элемента не было установлено в первый раз, когда вы сюда попали, заставляя какую-то белую логику внутри цикла. Общее правило большого пальца читается, затем проверяют. Тест перед чтением не так полезен. Во-первых, нет ничего, чтобы проверить, но настоящая проблема заключается в том, что вы используете непроверенные данные или должны включить другой тест, чтобы поймать его.

Прочтите, затем проверьте.

{ 
    cout<<"Enter the name of the item."<<'\n'; 
    cin>>item_name; 

Получить название товара. Groovy-иш.

if (item_name == SENTINEL) 
    { 
     cin>>item_name; 

ОК. Неплохо, но зачем здесь получить другое item_name?

 myfile<<"Thank you for your entries"<<'\n'; 
     myfile<<item_name<<"#"<<price<<endl; 
     myfile.close(); 

     break; 

break выходит из цикла или switch. Итак, мы идем.

} 
    else 
    { 
     cout<<"Enter the price of the item."<<'\n'; 
     cin>>price; 

Чтение в числовых значениях имеет несколько опасностей, которые вы должны соблюдать. Большой, если любой пользовательский тип не может быть превращен в price, cin переходит в режим ошибок и не будет возвращаться, пока ошибка не будет очищена. И прежде чем вы попытаетесь получить цену снова, данные мусора должны быть удалены.

Элегантная вещь о cin >> x возвращается cin. Это позволяет вам складывать команды. cin>>a>>b>>c>>d. cin, и все его потоковые братья, имеют встроенный логический оператор, который вы можете использовать в тестах. Если cin все еще в хорошем состоянии, все считывания завершены успешно, его можно протестировать и вернет true.

Это позволяет вам делать что-то вроде if (cin>>a>>b>>c>>d) и проверять, что все чтения были хороши одним выстрелом.

} 
} 

Применение чтения, то тест, мы получаем

while(cin>>item_name && // read in an item name 
     item_name != SENTINEL) // and then test that it isn't the sentinel 

Эти тупые выглядящие немного коды о безопасном способе сделать это. Он даже поймает и выйдет cin приходит к неожиданному концу. Не так часто бывает с cin, но это отличный способ проверить конец файла.

{ 
    while (!(cin >> price)) // keep looping until the user gives a number 
    { // if we're here, the user didn't give a good number and we have to clean up 
     // after them. Bad user. Bad. Bad. 

В стороне, не делайте этого трюка с файлом. Файл может закончиться. Вам нужно будет протестировать файл для завершения файла и выйти из него, прежде чем продолжить очистку.

 // clear the error 
     cin.clear(); 
     // throw out everything the user's typed in up to the next line 
     cin.ignore(numeric_limits<streamsize>::max(), '\n'); 
    } 
    // user got out of the while of doom. They must have entered a number. 

Welllll Фактически, это просто должно было начаться с числа. cin >> довольно немой и пропустит 1234abcd, взяв 1234 и оставив abcd для следующего чтения. Это может привести к неприятным сюрпризам. В этом случае abcd завершится следующим образом: item_name. то, что должно было быть следующим item_name, станет следующим price и плохими ручками Ju-ju оттуда.

И теперь вернемся к коду.

item temp; // make a temporary item 
    temp.name = item_name; // set the values correctly 
    temp.price = price; 
    items.push_back(temp); // put them in the list. 

Вы можете сэкономить немного работы здесь, добавив конструктор item и используя vector «s emplace_back метод. Поищи это. Очень удобно.

} 

И снова без комментарив:

while(cin>>item_name && // read in an item name 
     item_name != SENTINEL) // and then test that it isn't the sentinel 
{ 
    while (!(cin >> price)) // keep looping until the user gives a number 
    { // if we're here, the user didn't give a good number and we have to clean up 
     // after them. Bad user. Bad. Bad. 
     // clear the error 
     cin.clear(); 
     // throw out everything the user's typed in up to the next line 
     cin.ignore(numeric_limits<streamsize>::max(), '\n'); 
    } 
    // user got out of the while of doom. They must have entered a number. 
    item temp; // make a temporary item 
    temp.name = item_name; // set the values correctly 
    temp.price = price; 
    items.push_back(temp); // put them in the list. 
} 

Теперь у вас есть vector полный item с для печати. Stack Overflow полна примеров того, как это сделать, но лучше всего, если сначала сделать снимок.

-2

Почему у вас есть дополнительный вызов cin внутри оператора if, проверяющего запись? Я думаю, что не нужно.

Для решения проблемы с вашими вводами вы сохраняете только последние введенные значения, потому что каждый раз, когда цикл запускается снова, он переписывает переменные.

Чтобы решить эту проблему, вам необходимо использовать массив для хранения элементов. Если вы хотите сделать так, чтобы вы могли запускать цикл, введите как можно больше входов, вам понадобится реализовать динамический массив.

Вот как реализовать динамический массив http://www.learncpp.com/cpp-tutorial/6-9a-dynamically-allocating-arrays/

+1

Почему бы вам не просто использовать ['std :: vector'] (http://en.cppreference.com/w/cpp/container/vector) вместо того, чтобы изобретать колесо? –

+0

Он учится, поэтому я решил, что лучше всего начать с того, как большинство людей учатся. –

+1

Я бы не стал предлагать, чтобы начинающий начал путь к работе с необработанными указателями и управлением памятью; не все учебники хороши. –

Смежные вопросы