Question

As part of a school project, I would like to get an inventory *.txt file into an array in C++ and eventually back to a *.txt file at a later part in the program.

The text file will start out with 10 rows that will represent grocery story items and will include three columns that represent the name, price, and quantity of the items. I have been able to read from the file, even add numbers in front of each row that is displayed. Now, I would like to get the text file into a string array so that the "employee" user can make changes to items one at a time and then I can dump that array back into a *.txt file.

The code below is what I have been trying so far. I can get the count of rows in the file, but can't seem to get the columns counted or the data in the rows displayed. When I run the program, I get what appear to be 10 empty lines after it displays the rows (10) and Cols(0).

The columns in the *.txt file are normally separated by a space. I tried a tab, and tried: while(getline(invFile, lines, '\t'); which just caused the console to display what I am guessing was a memory address and then crashed.

Unfortunately, we have not gotten very far into debugging programs, and from the look of the syllabus, I don't think that will be covered very thoroughly, so I don't know how to troubleshoot any further. I have spent the last couple of hours Google-ing, and have gotten to the point that I actually need to ask for help.

The project involves a lot more than this component, but I really am stuck on this part. I am not asking for someone to do this for me, but if anyone has any idea what I am doing wrong and can point me in the best direction to get a text file into a multi-dimensional array, I would really appreciate it.

Thank you.

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


    int row = 0;
    int col = 0;

    using namespace std;

    int main()
    {
        string lines;
        int x;
        string textArray[2][2];
        ifstream invFile;
        invFile.open("inventory.txt");

        if(invFile.fail()){
            cerr << "The file cannot be opened!";
            exit(1);
        }

        cout << "\n" << endl;
        while(invFile.good()) {

            while(getline(invFile, lines)) {
                istringstream streamA(lines);
                col = 0;
                while(streamA >> x) {
                    cout << x;
                    textArray[row][col] = x;
                    col++;
                }
                row++;
            }
        }

        invFile.close();

        cout << "Rows: " << row << endl;
        cout << "Cols: " << col << endl;
        cout << "\n" << endl;

        for(int i=0; i<row; i++){
            for(int j=0; j<col; j++){
                cout << "Line: " << i << textArray[i][j] << ".";
            }
            cout << "\n";
        }

        return(0);
    }
=============================
    inventory.txt:

    Apples 1.25 20
    Oranges 1.75 20
    Kiwi 2.50 15
    Pineapples 5.50 20
    Tomatoes 1.50 20
    Onions 2.00 20
    Corn 1.80 20
    Carrots 2.30 20
    Milk 4.50 20
    Cheese 2.25 20
Was it helpful?

Solution 2

I'd like to suggest you add some print lines in the important step -- which I think also is a fast&good "debug" method. So that you can find where you wrong easily. For example in your code, seems textArray wasn't assigned, so add some print nearby:

while(getline(invFile, lines)) {
                cout <<"lines: " << lines << endl; //test enter here
                istringstream streamA(lines);
                col = 0;
                while(streamA >> x) {
                    cout << "x is" << x; //test if enter here
                    textArray[row][col] = x;
                    col++;
                }
                row++;
            }

Through the output, the lines is ok but cout << "x is" << x; wasn't printed, which means the while(streamA >>x) condition is false, why?

Go to find the library function called, std::istringstream x is int type but col 1 value is Apples, operator << will return NULL, it's unreasonable assing Apples to an int, till now, found point 1. If have to use int or float to store the numbers, use some convert API like atoi, atof.

After change x from int to string, got segmentation falut, it's obviously that textArray[2][2] is not enough to store all the information. "Out of range" is the reason of segmentation fault, so make a large array to test continue until passed.

OTHER TIPS

I would suggest that you create a struct or class to hold the data. From each line of text, extract the fields appropriately and them to your struct. Then, keep a list of those structs using std::vector.

#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <sstream>
#include <array>
#include <vector>
#include <cstdlib>

using namespace std;

struct Row
{
   vector<string> columns;
};

int main()
{
   string line;
   vector<Row> rows;
   ifstream invFile;
   invFile.open("inventory.txt");

   if(invFile.fail()){
       cerr << "The file cannot be opened!";
       exit(1);
   }

   cout << "\n" << endl;
   while(invFile.good()) {

       while(getline(invFile, line)) 
       {
          Row row;
          istringstream streamA(line);
          string col;
          while ( streamA >> col )
          {
             row.columns.push_back(col);
          }
          rows.push_back(row);
       }
   }

   invFile.close();

   cout << "Rows: " << rows.size() << endl;
   cout << "Cols: " << rows[0].columns.size() << endl;
   cout << "\n" << endl;

   for(int i=0; i<rows.size(); i++){
       for(int j=0; j<rows[i].columns.size(); j++){
           cout << "Line: " << i << " " << rows[i].columns[j] << "\n";
       }
       cout << "\n";
   }

   return(0);
}

There's a couple ways you could do this. The easiest would be to just put something like 3,10 at the top of the file, and then you know three columns and 10 rows. Since your writing this after modification, you would just need to make sure that those numbers get written correctly.

If you want to learn some more advanced methods, then your life will be easier AFTER you learn a bunch more.

If you used a vector, using something like vector< vector<string> > you could just read to a stringstream and then split the line read and put it into the vector

fstream file(...);
string tempString;
vector< vector<string> > list;

// Get a full line
while(getline(file, tempString, '\n'){

    // Create a StringStream and store tempString in it for further manipulation
    stringstream ss;
    ss << tempString;
    vector<string> tempVec;

    // Get each column from this row
    while(getline(ss, tempString, '\t'){
        // Put each column into a vector
        tempVec.push_back(tempString);
    }

    // Put the entire vector into our list vector
    list.push_back(tempVec);
}

The benefit of this second method is twofold. First, it's very easy. I'm guessing you don't know how it works, but some easy Google searches on keywords you don't know, and you'll find out fast enough. The second is it allows (theoretically) unlimited rows, and unconstrained columns. By that, I mean one row could have 20 columns, one could have 2, and there would be no wasted space.

Note that you should NOT use the skeleton code I showed before researching it. If you don't have at least a general idea of what is happening here, then you'll just cause problems for yourself later on. I'm not going to explain everything here, because other people have done that already. Also, since you're learning this in school, you'll get to these things eventually, so you'll just be getting ahead. The one main constraint would be if your project requires arrays, in which case, my first solution would be the best option.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top