У вас уже есть подход к реализации класса, использующий STL std::vector
для хранения каждого из компонентов каждой строки как единой единицы, предоставленной @ JosephLarson . С помощью реализации класса вы можете предоставить функции-члены для работы с сохраненными данными, чтобы создать абстракцию того, чем является ваша ферма.
Если это немного выходит за рамки вашего обучения, вы можете подойти к нему, сохранивдва набора значений. Один для текущей фермы, для которой вы собираете значения, и временный набор, в который вы читаете данные из вашего файла. Вместо двух наборов по 5 переменных каждый раз, когда вам нужно согласовать различные типы данных как одну единицу, вы должны подумать struct
или class
(обе обеспечивают одинаковую функциональность в C ++, различие заключается в том, что по умолчаниюдоступ к struct
членам - public:
, тогда как по умолчанию для class
членов - private:
.
Как упоминалось в моих комментариях ранее, ваш нынешний подход к попытке чтения данных с помощью while(!inFile.eof())
закончитсяесли сбой. См. Почему! .eof () внутри условия цикла всегда неверно. и Почему iostream :: eof внутри условия цикла считается неправильным?
Вместо этого, для общего подхода, вместо того, чтобы пытаться читать части строки с разными вызовами getline
непосредственно из вашего файлового потока, гораздо лучше прочитать всю строку за раз, а затем создать std::stringstream
и извлеките необходимую информацию из потока строк. Предотвращает частичное чтение или форматирование ошибки от точки ошибки до концавашего файла.
Подход прямой, начинайте как есть, но включайте также <sstream>
. Например, вы можете включить необходимые заголовки и объявить простой struct
для хранения различных частей каждой строки, объявить экземпляр структуры для использования в вашем коде, проверить, что указан хотя бы один аргумент для предоставления имени файла, прочитатьимя файла в качестве первого аргумента вашей программы и откройте поток файлов для чтения с помощью:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
struct farmdata {
std::string name, item;
size_t qty;
double cost, total;
};
int main (int argc, char **argv) {
if (argc < 2) {
std::cerr << "error: filename required as 1st argument.\n";
return 1;
}
farmdata farm = {"", "", 0, 0.0, 0.0};
size_t farmcount = 0;
std::string line;
std::ifstream f (argv[1]);
...
На этом этапе, а не while(!inFile.eof())
, управляйте циклом чтения с фактическим чтением строки встрока line
, например,
while (getline (f, line)) {
...
Теперь просто создайте строку stringstream
из строки, из которой вы можете прочитать name, qty, item, cost & total
без риска оставить посторонние символы в потоке непрочитанными в случае ошибки синтаксического анализаили несоответствие типов. Это довольно просто сделать. Вы также захотите объявить временный экземпляр вашей структуры для чтения значений, которые позволят вам сравнить name
фермы с текущим именем фермы, для которой вы собираете данные, например,
std::istringstream ss (line);
farmdata tmp;
Теперь просто считайте значения во временную структуру из строкового потока ss
так же, как из вашего файлового потока, и затем сравните значения с текущими значениями в farm
(обратите внимание, что структура farm
была инициализирована нулем, чтобы можно было проверитьfarm.name.length()
( примечание: ваш farmcount
обновляется только тогда, когда имя прочитано в ноль *1044* - ноль, указывающий на то, что первая строка читается в tmp
):
if (getline (ss, tmp.name, ',')) {
if (ss >> tmp.qty && ss >> tmp.item && ss >>
tmp.cost && ss >> tmp.total) {
if (farm.name.length() == 0) {
farm = tmp;
farmcount++;
}
else if (tmp.name == farm.name) {
farm.qty += tmp.qty;
farm.total += tmp.total;
}
else {
std::cout << farm.name << " " << farm.qty <<
" items contributed totaling $" << farm.total << '\n';
farm = tmp;
farmcount++;
}
}
}
}
*
tmp
отличается от
farm.name
или в первой строке, считанной из файла)
После выхода из цикла чтения все, что остается, - это вывести данные для последнего farm
чтения из файла и вывести общее количествоfarmcount
, которые участвовали на этой неделе,
std::cout << farm.name << " " << farm.qty <<
" items contributed totaling $" << farm.total << "\n\n";
std::cout << "There were " << farmcount <<
" unique farms contributing to this week's event." << '\n';
}
Пример использования / Вывод
Если вы реализуете что-то похожее на вышеописанное, вы обработаете yнаш файл и получить что-то похожее на:
$ ./bin/farmtotal dat/farms.txt
Collins Farm 43900 items contributed totaling $29413
Bart Smith Farms 34910 items contributed totaling $34560.9
Allen Farms 117 items contributed totaling $63.18
River Run Farm 103 items contributed totaling $66.95
Big Top Farm 10625 items contributed totaling $5622.3
Marble Farm 108 items contributed totaling $35.64
Food For Life Inc. 192 items contributed totaling $164.46
Johnson Farms 121 items contributed totaling $26.62
A1 Farm 5702 items contributed totaling $4038.84
Looney Tunes Farm 102 items contributed totaling $49.98
Wolfe Creek Farm 302 items contributed totaling $265.92
James Farm 47 items contributed totaling $31.96
Weaver Farms 575 items contributed totaling $482.5
Pore Boy Farms 670000 items contributed totaling $529300
Rutherford Farms Inc. 1468 items contributed totaling $1189.4
Javens Farm 129000 items contributed totaling $56760
Harrison Farms 8001 items contributed totaling $8721.09
Setzer Farms Inc. 1352 items contributed totaling $1073.08
Pikes Peak Farm 1045 items contributed totaling $825.55
Holland Area Farms 10001 items contributed totaling $6900.69
There were 20 unique farms contributing to this week's event.
Недостаток простого использования метода «дюйм-червя» для проверки текущего имени, прочитанного по последнему, состоит в том, что вы не храните свои данные в любом типе массива. или vector
, что ограничивает вашу способность сортировать или иным образом манипулировать полным набором данных, чтобы получать информацию в любой другой форме, отличной от "прочитанной из файла".
Вы также можете дополнительно настроить форматирование вывода, включив заголовок Standard library header <iomanip>
и используя std::setw()
для общей ширины поля вместе с std::fixed
и std::count.precision()
для форматирования чисел с плавающей запятой.
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.