0

The code is supposed to display this but my code either displays the framework without any values or it just loops infinity when I try to enter values in a .txt file.

This is for my algorithm class. It'll only display the framework or loop infinitely. I've attempted the getline functions but I'm not sure where to put them into my code because it usually causes several errors.

#include<iostream>
#include<fstream>
#include<string>
using namespace std;

void headerModule();
void detailsModule();

int main ()
{
    headerModule();
    detailsModule();

    return 0;
}

void headerModule()
{
    cout<<"Brewster's Used Cars, Inc."<<endl;
    cout<<"Sales Report"<<endl;
    cout<<endl;
    cout<<"Salesperson ID       Sales Amount"<<endl;
    cout<<"====================================================="<<endl;
}

void detailsModule()
{
    int salespersonID, currentID;
    float sales;
    float totalSales = 0;
    float allSales = 0;

    ifstream salesFile;
    salesFile.open("sales.txt");
    salesFile>>salespersonID>>sales;

    currentID = salespersonID;

    while(!salesFile.eof())
    {
        if(salespersonID!=currentID)
        {
            cout<<"Total sales for this salesperson:"<<"$" 
            <<totalSales<<endl;
            cout<<endl;
            currentID=salespersonID;
            totalSales=0;
        }

        cout<<salespersonID<<""<<"$"<<sales<<endl;
        totalSales = totalSales+sales;
        allSales = allSales+sales;
        salesFile>>salespersonID>>sales;
    }

    cout<<"Total sales for this salesperson: "<<"$"<<totalSales<<endl;
    cout<<"Total of all sales: "<<"$"<<allSales<<endl;
    salesFile.close();

}

This is what it should look like:

Brewster's Used Cars, Inc.
Sales Report

Salesperson ID     Sale Amount
======================================
100                $10,000.00
100                $12,000.00
100                $5,000.00
Total sales for this salesperson: $27,000.00

101                $14,000.00
101                $18,000.00
101                $12,000.00
Total sales for this salesperson: $44,500.00

102                $13,000.00
102                $14,000.00
102                $20,000.00
Total sales for this salesperson: $48,000.00
Total of all sales: $119,500.00

I either just get this:

Brewster's Used Cars, Inc.
Sales Report

Salesperson ID     Sale Amount
======================================
Total sales for this salesperson: $0
Total of all sales: $0

Or it loops indefinitely when I try to enter values in the .txt file.

  • There are so many senmantic errors in this code that it is hard to tell everything in this comment. Your main issue is that you do not read anything from the file in your while loop. And because you read nothing from the file, there will be never an "end of file" (eof), resulting in an endless loop. You should first write the program data on a piece of paper, think *what* you want to do, then *how* you do it and then write the code (typing in C++ code) as a last activity. – Armin Montigny Nov 11 '19 at 06:22
  • 3
    [SO: Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/q/5605125/7478597) – Scheff's Cat Nov 11 '19 at 06:32
  • Isn't the "salesFile>>salespersonID>>sales;" in the while loop reading the .txt file? – Ryan Beam Nov 11 '19 at 06:32
  • What exactly does your `sales.txt` look like? Your code works fine for me (modulo the issue with `eof()` in the `while` loop condition). – Daniel Junglas Nov 11 '19 at 08:23
  • You need to check if the reading succeeds, not just for eof. `while(salesFile>>salespersonID>>sales)` will execute the loop only if the two ints have been successfully read from the stream. – churill Nov 11 '19 at 08:32

2 Answers2

1

I would like to show a "more-C++" example.

We could create a tiny class holding the sales persons ID and the amount. We call this class "Transaction". The extractor operator will be overloaded, since The advantage is that that we can simple use the extractor operator to read data from the file.

while (testFile >> transaction)

So we read the file, and then put it in a std::map. The std::map will store a vector of sales amount for each sales person. So the overall reading and gouping of data boils down to 2 simple lines of code:

    while (testFile >> transaction) {
        salesPerPerson[transaction.id].emplace_back (transaction.amount);

The rest of the program is some simple output routine. The whole programm will then look like this:


#include <vector>
#include <iostream>
#include <sstream>
#include <iterator>
#include <map>
#include <iomanip>

std::istringstream testFile {R"(100 1000
101 1010
102 1020
103 1030
100 1001
101 1011
102 1021
103 1031
100 1002
101 1012
102 1022
103 1032
)"};

using ID = size_t;
using Amount = float;

struct Transaction {

    ID id{};
    Amount amount {};

    friend std::istream & operator >> (std::istream & is, Transaction & t)
    {
        std::string line{};
        if (std::getline (is, line))  {
            std::istringstream iss (line);
            iss >> t.id >> t.amount;
        }
        return is;
    }
};


int main () {
    Transaction transaction  {};
    std::map <ID,std::vector<Amount>> salesPerPerson {};

    // Read all transactions from file and group them
    while (testFile >> transaction) {
        salesPerPerson[transaction.id].emplace_back (transaction.amount);
    }

    // Output
    Amount totalSum  {0.0};
    Amount personSum  {0.0};

    std::cout << "\n\nBrewster's Used Cars, Inc.\nSales Report\n\nSalesperson ID     Sales Amount\n======================================\n";
    for (const auto &[id, amountList] : salesPerPerson)
    {
        personSum = 0.0;
        for (const Amount& amount : amountList)
        {
            personSum += amount;
            std::cout << std::left << std::setw (19) << id << "$"  << amount << "\n";
        }
        std::cout << "Total sales for this salesperson: $" << personSum << "\n\n"; 
        totalSum += personSum;
    }
    std::cout << "Total of all sales:               $" << totalSum << "\n";

    return 0;
}

Please note. I do not have files on SO. Therefore I used std::istringstream as a source file. Of course you can use any std::istream like a std::ifstream and with that reading from a file . . .

Armin Montigny
  • 7,879
  • 3
  • 11
  • 29
0

I think it's looping because it is unable to open the required file. The first thing you need to do is to make sure that the desired file has been successfully opened like this.

    std::ifstream salesFile;
    salesFile.open("sales.txt");

    if (!salesFile) {
        std::cerr << "Failed to open file" << std::endl;
        return;
    }

With your current while loop condition, it will loop if the application is unable to open the file. Using the while(!salesFile.eof()) is not the recommended approach as the eof flag is set only when the file is read, after the last character in the file has already been read. That is to check the flag you need to read the file first. In your code, this seems to work as you are reading the file (salesFile>>salespersonID>>sales) before checking the while condition.

Here's a working code using getline and the required output formatting. You can use std::put_money() to format the values into the required currency format.

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <iomanip>

void headerModule()
{
    std::cout<<"Brewster's Used Cars, Inc."<< std::endl;
    std::cout<<"Sales Report"<< std::endl;

    std::cout<< std::endl;
    std::cout<< std::setw(20) << std::left << "Salesperson ID"
        << std::setw(20) << std::left << "Sales Amount" << std::endl;

    std::cout << std::setw(40) << std::setfill('=') << "" << std::setfill(' ') << std::endl;
}

void detailsModule()
{
    int salespersonID;
    int currentID;
    double sales;
    double totalSales = 0;
    double allSales = 0;

    std::string line;

    std::ifstream salesFile;
    salesFile.open("sales.txt");

    if (!salesFile) {
        std::cerr << "Failed to open file" << std::endl;
        return;
    }

    /* for printing money */
    /* NOTE: std::put_money accepts args in cents */
    std::cout.imbue(std::locale("en_US.utf8"));

    /* To set the currentID on first run */
    bool first_run = true;

    while(std::getline(salesFile, line)) {
        std::stringstream ss {line};

        ss >> salespersonID;
        ss >> sales;

        if (first_run) {
            currentID = salespersonID;
            first_run = false;
        }

        if(salespersonID != currentID)
        {
            std::cout << "Total sales for this salesperson: "
            << std::put_money(totalSales * 100) << std::endl;

            std::cout << std::endl;

            currentID = salespersonID;
            totalSales = 0.0;
        }

        std::cout << std::setw(20) << std::left << salespersonID 
                  << std::showbase << std::put_money(sales * 100) /* put_money accepts cents */
                  << std::endl;

        totalSales = totalSales + sales;
        allSales = allSales + sales;
    }

    /* print total sales for last entry */
    std::cout << "Total sales for this salesperson: "
            << std::put_money(totalSales * 100) << std::endl;

    std::cout << "Total of all sales: " << std::put_money(allSales * 100) << std::endl;

    salesFile.close();

}

int main ()
{
    headerModule();
    detailsModule();

    return 0;
}

Example sales.txt

100 10000.00
100 12000.00
100 5000.00
101 14000.00
101 18000.00
101 12000.00
102 13000.00
102 14000.00
102 20000.00

Output

Brewster's Used Cars, Inc.
Sales Report

Salesperson ID      Sales Amount        
========================================
100                 $10,000.00
100                 $12,000.00
100                 $5,000.00
Total sales for this salesperson: $27,000.00

101                 $14,000.00
101                 $18,000.00
101                 $12,000.00
Total sales for this salesperson: $44,000.00

102                 $13,000.00
102                 $14,000.00
102                 $20,000.00
Total sales for this salesperson: $47,000.00
Total of all sales: $118,000.00

Yasir Khan
  • 585
  • 3
  • 9