0

I want to print out struct variable which is customer name and total price from a file.txt using dev c++, but the screen prints out no result. The screen is blank but no error occured.

This is the content of the file

File name :Fruit Order.txt
Jean;1;Apple;1;1;
Alex;2;Apple;Kiwi;1;1;1;2;
Adam;2;Kiwi;Watermelon;2;1;2;5;

This the coding

#include<iostream>
#include<fstream>
using namespace std;
struct CustInfo{
    string custName;
    int order;
    double totalPrice;
};
struct OrderInfo{
    string fruitName;
    int quantity;
    double price;
};
int main(){
    int x = 0, y = 0;
    double temp = 0;
    CustInfo CI[3];
    ifstream file1;
    file1.open("Fruit Order.txt");
    while(!file1.eof()){
        for(x; x < 3; x++){
            getline(file1, CI[x].custName, ';');
            file1 >> CI[x].order;
            file1.ignore(1, ';');
            OrderInfo OI[CI[x].order];
            for(y; y < CI[x].order; y++){
                getline(file1, OI[y].fruitName, ';');
                file1 >> OI[y].quantity;
                file1.ignore(1, ';');
                file1 >> OI[y].price;
                file1.ignore(1, ';');
                temp += (OI[y].quantity * OI[y].price);
            }
            CI[x].totalPrice = temp;
            temp = 0;
        }
    }
    for(x = 0; x < 3; x++){
        cout << CI[x].custName << endl;
        cout << CI[x].totalPrice << endl;
    }
    file1.close();
    return 0;
}
yusuka
  • 9
  • 2
  • Instead of ```OrderInfo OI[CI[x].order];``` I think you will need to use ```OrderInfo* OI = new OrderInfo[CI[x].order];```. Also, the text file has all fruit names first then other integers. So, maybe you will need to read all names first and then read other numbers. – Mohamed Akram Jul 10 '21 at 08:04
  • 1
    Probably not the bug you're dealing with, but you owe it to yourself to read [Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/questions/5605125) to save yourself from some confusion later. – user4581301 Jul 10 '21 at 08:06
  • Suggestion. As you read stuff in from the file, print it out to see what you are reading. You might be surprised. I think that problem I linked above IS contributing to your bug. – user4581301 Jul 10 '21 at 08:25
  • Thank you for the comment, but my problem already solved because I forgot to ignore \n in my file, thank you for the advice. – yusuka Jul 15 '21 at 23:27

2 Answers2

0

Here I put some changes to your code with //----> before them

#include<iostream>
#include<fstream>
using namespace std;
struct CustInfo{
    string custName;
    int order;
    double totalPrice;
};
struct OrderInfo{
    string fruitName;
    int quantity;
    double price;
};
int main(){
    int x = 0, y = 0;
    double temp = 0;
    CustInfo CI[3];
    ifstream file1;
    file1.open("Fruit Order.txt");
    // ---> dummyString to read unwanted strings ... you can use it to read unwanted ; but I use it for \n
    string dummyString;
    //-----> removed while ( user4581301  recommendation )
    // while(!file1.eof()){
        for(x; x < 3; x++){
            getline(file1, CI[x].custName, ';');
            file1 >> CI[x].order;
            file1.ignore(1, ';');
            // OrderInfo OI[CI[x].order];
            //------> added this (dynamic allocation as order is known only at runtime)
            OrderInfo* OI = new OrderInfo[CI[x].order];
            for(y; y < CI[x].order; y++){
                getline(file1, OI[y].fruitName, ';');
            }
            // split the two loops because all fruitNames come before other numbers. So, read all fruitNames first
            for (y = 0;  y < CI[x].order; y++)
            {
                file1 >> OI[y].quantity;
                file1.ignore(1, ';');
                file1 >> OI[y].price;
                file1.ignore(1, ';');
                temp += (OI[y].quantity * OI[y].price);
            }
            
            CI[x].totalPrice = temp;
            temp = 0;
            // --------> added this | or make it local (inside for loop)
            // -- this is because you access OI[y] and its size is 3 while y increases and is outside for(x...)
            y= 0;

            // ---> deleted OI because we don't need it
            delete[] OI;
            // ----> if you delete this, the custName string will have \n character in it (new line)
            getline(file1,dummyString,'\n');
        }
    for(x = 0; x < 3; x++){
        cout << CI[x].custName << endl;
        cout << CI[x].totalPrice << endl;
    }
    file1.close();
    return 0;
}
Mohamed Akram
  • 416
  • 4
  • 12
  • Recommendation: rather than `OrderInfo* OI = new OrderInfo[CI[x].order];`, prefer `std::vector OI(CI[x].order);`. You should only pull `new` out of the tool box when `new` and `malloc` are the only things left. – user4581301 Jul 10 '21 at 08:28
  • 1
    Actually removing the `while` wasn't my recommendation. Having the `while` was wrong two different ways, and I focused on the first one: EOF is only set AFTER reading and finding EOF. If you check before you start reading, you can read off the end of the file after the check and not notice in time. Had I looked further at the time I would have recommended something more like option 2 [in this answer](https://stackoverflow.com/a/7868998/4581301) – user4581301 Jul 10 '21 at 08:35
  • Thank you for the comment, but my problem already solved because I forgot to ignore \n in my file, thank you for the advice. – yusuka Jul 15 '21 at 23:27
0

To be honest. There are many problems in your code. Biggest issue is that you have 0 lines of comments in your code. With that it is only hardly readable.

Then, the input data has a clumsy format, which makes it hard to read. Basically, quantities and price should follow immediately after then product name, and better put in a separate line. Anyway. It is like ist is.

So, and then you have dynamic data, That means, you do not know in advance, how big your arrays will must be. In the below example I use new and raw pointers for owned memory. This you should normally never do and use always a std::vector instead. But ok, lets see.

The data model, so, how and with with structure you want to model the data is also and always essential. Please see my approch in the example below.

The additional difficulty while parsing the input line is the change between formatted and unformatted input. Special care must be taken to handle the semicolon correctly.

Then, you would add member functions in your structs to handle the work. Objects should be encapsulated.

All this I will not do in the below example solution. I stick more or less to your programming style, but add a lot of comments.

Please see:

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

struct Product{
    std::string productName{};
    unsigned int quantity{};
    double price{};
    double totalPriceProduct{};
};
struct Order {
    std::string customerName{};
    Product *products{};
    unsigned int numberOfProducts;
    double totalPriceOrder{};
};
struct OrderDatabase {
    Order* orders{};
    unsigned int numberOfOrders{};
    double totalPrice;
};

int main() {

    // Here we will store all our orders
    OrderDatabase orderDatabase{};

    // Open the source file
    std::ifstream fileStream{ "r:\\Fruit Order.txt" };

    // Count, how many orders we do have in the file
    std::string lineWithOrder{};

    // Read all lines from file an throw content away. Count the lines
    while (std::getline(fileStream, lineWithOrder) and not lineWithOrder.empty())
        ++orderDatabase.numberOfOrders;

    // Reset stream. Clear eof bit and reset file pointer
    fileStream.clear();
    fileStream.seekg(0, std::ios::beg); // back to the start!

    // Now dynamically allocate memory for our orders
    orderDatabase.orders = new Order[orderDatabase.numberOfOrders];
    
    char dummy; // for reading the semicolon and throw it away
    // Read all data 
    unsigned int orderIndex{};

    // -----------------------------------------------------------------------------------------------------------
    // Read all data
    do {
        // Read customer name
        std::getline(fileStream, orderDatabase.orders[orderIndex].customerName, ';');

        // How many products are in this order?
        fileStream >> orderDatabase.orders[orderIndex].numberOfProducts >> dummy;

        // Allocate memory for new products
        orderDatabase.orders[orderIndex].products = new Product[orderDatabase.orders[orderIndex].numberOfProducts];

        // Read product names
        for (unsigned int productIndex = 0; productIndex < orderDatabase.orders[orderIndex].numberOfProducts; ++productIndex) {
            std::getline(fileStream, orderDatabase.orders[orderIndex].products[productIndex].productName, ';');
        }

        // Read product quantity and price
        for (unsigned int productIndex = 0; productIndex < orderDatabase.orders[orderIndex].numberOfProducts; ++productIndex) {

            fileStream >> orderDatabase.orders[orderIndex].products[productIndex].quantity >> dummy;
            fileStream >> orderDatabase.orders[orderIndex].products[productIndex].price >> dummy;

            // Calculate total price for product
            orderDatabase.orders[orderIndex].products[productIndex].totalPriceProduct = orderDatabase.orders[orderIndex].products[productIndex].quantity * orderDatabase.orders[orderIndex].products[productIndex].price;

            // Accumulate prices in oder
            orderDatabase.orders[orderIndex].totalPriceOrder += orderDatabase.orders[orderIndex].products[productIndex].totalPriceProduct;

            // Accumulate overall total price
            orderDatabase.totalPrice += orderDatabase.orders[orderIndex].products[productIndex].totalPriceProduct;;
        }

        // Read next line
        ++orderIndex;
        
    } while (fileStream and orderIndex < orderDatabase.numberOfOrders);

    // -------------------------------------------------------------------------------------------------------
    // Show result to user
    std::cout << "\n\nThere are " << orderDatabase.numberOfOrders << " orders in the database. Details:\n";

    for (orderIndex = 0; orderIndex < orderDatabase.numberOfOrders; ++orderIndex) {
        // Show one order
        std::cout << "\nOrder number " << orderIndex + 1 << " for Customer: " << orderDatabase.orders[orderIndex].customerName << " with " << orderDatabase.orders[orderIndex].numberOfProducts << " products\n";

        // Show product in this order
        for (unsigned int productIndex = 0; productIndex < orderDatabase.orders[orderIndex].numberOfProducts; ++productIndex) {
            std::cout << "Product: " << orderDatabase.orders[orderIndex].products[productIndex].productName << " \t Quantity: " << orderDatabase.orders[orderIndex].products[productIndex].quantity << " \tPrice: " <<
                orderDatabase.orders[orderIndex].products[productIndex].price << "   \t Total -->  " << orderDatabase.orders[orderIndex].products[productIndex].totalPriceProduct << '\n';
        }
        // Show total order price
        std::cout << "\nTotal price of this order: " << orderDatabase.orders[orderIndex].totalPriceOrder << '\n';
    }

    // Show overall total
    std::cout << "\n\nTotal price overall: " << orderDatabase.totalPrice << '\n';

    // Free memory
    for (orderIndex = 0; orderIndex < orderDatabase.numberOfOrders; ++orderIndex) {
        delete[] orderDatabase.orders[orderIndex].products;
    }
    delete[] orderDatabase.orders;

    return 0;
}

As said. I would not do it that way, but use more advance C++ techniques.

But please try this in the beginning.

A M
  • 14,694
  • 5
  • 19
  • 44
  • Thank you for the comment, but my problem already solved because I forgot to ignore \n in my file, thank you for the advice. – yusuka Jul 15 '21 at 23:26