Data structures help

Pages: 12
Hello. So this code isn't working. I have to create a program that:
- define class cust(I already did this part)
- create an array of cust (size 10)to hole the data of the class.
- read the date from a file(everything from the class)
- call a function print cust(this function will print all the data in table format)....first, last, state, sales history(0,1,2), units
- Read the data from a file (you may break up the strings and numeric values any way
you choose (separate lines may be easier)
- Make a function call to a function called printcust. This function will print all the
data for all of the customers (in tabular format similar to the layout of the input
data below).
- Make a function call to a function called sortname which will sort the cust array
alphabetically by last name.
- Make a function call to the function printcust.
- Make a function call to a function called sortsales. This function will sort the above
array in descending order of the total sales.
- Call the function printcust

I don't know what I'm doing wrong.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>

using namespace std;

class sales_info{
      public:

      };
class customer{
      public:
      string first;
      string last;
      string state;
      double sHistory[3]; // Sales history for three years.
      double totalSales; // Total sales (adding all three years together)
      int purchaseUnits;
      };
void printcust(customer[], int);
void sortname(customer[], int);
void sortsales(customer[], int);


int main () {
	customer cust[10];
	int i;
	
	for(int i = 0; i < 10; i++)
	customer cust[i];
	
	fstream infile;
	infile.open("data.txt");
	
	getline(infile, cust[i].first);
	getline(infile, cust[i].last);
	getline(infile, cust[i].state);
	
	infile >> customer.purchaseUnits[]

}


Last edited on
I don't know what I'm doing wrong.

You need to explain in greater detail what you expect to happen and what actually is happening.

I can see two possible problems:

1. you are not opening the data file, it's located in "the wrong place."

2. mixing std::getline and operator>> when extracting data can cause problems.

Posting some example content from your data file would help us as well.
What are lines 30, 31, and 40 meant to do?

-Albatross
Sorry. So it's not opening the data file. It's saved in the same folder as the program, so to be safe how would I copy the file path for extra security that it is pulling the file.

The program is supposed to fulfill all said bullet points in original posting. In total I am supposed to have about 3 tabular outputs.

File: data.txt

Contents of the file:
Lucky Louis NY
100 50 700
2000
Ariel Mermaid NC
250 100 80
5000
Marshall Mathers FL
20 100 200
1000
John Doeson LA
100 200 300
5000
Jane Fanner VA
50 40 200
1000

When compiling the output says:
 In function 'int main()':
40:20: error: expected primary-expression before '.' token
40:35: error: expected primary-expression before ']' token
Last edited on
Having compile errors negates my earlier possible problems. Let's get your code to compile successfully first.

Line 40 probably should be this:

infile >> cust[i].purchaseUnits;

The biggest problem you have is how you are reading the data from your file. You are only doing it once, after your for loop finishes.

Change line 31 to a single { bracket. Add a single } bracket to line 41.

Now you are reading data from your file 10 times.

Reading it badly, but 10 times.

Your customer's name, first and last, and state abbreviation are stored on a single line. std::getline reads the entire line, so you get (for example):

1. customer's first name: Lucky Louis NY
2. customer's last name: 100 50 700
3. customer's state: 2000
4. # of purchased units: Ariel Mermaid NC

Actually trying to read a string into an int will error out the input stream, so your program fails right from the start even if it opens the data file correctly.,

How could I fix it so that the program doesn't fail?
Because you have 3 lines of data for each customer you need to read, 2 lines have packed data to read.

Read all 3 lines using std::getline into a temp string.

ONE way to unpack the data with the first two lines is create a std::stringstream for each of the two lines. Then extract the data from the stringstream, assigning the data to the appropriate customer class data member.

https://en.cppreference.com/w/cpp/io/basic_stringstream/basic_stringstream
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

struct customer
{
    std::string first_name ;
    std::string last_name ;
    std::string state ;

    static const int NHIST = 3 ;
    double sales_history[NHIST] = {} ;

    int units_purchased = 0 ;
};

// Read the data from a file
// (you may break up the strings and numeric values any way you choose)
std::istream& get_cust( std::istream& stm, customer& cust )
{
    /* format
        Lucky Louis NY (first_name last_name state)
        100 50 700 (sales_history)
        2000 (units_purchased)
    */

    // we use the simplest approach; since no field contains white spaces and
    // the fields are separated by white space, just use formatted input for everything
    stm >> cust.first_name >> cust.last_name >> cust.state ; // line #1

    // range based loop: http://www.stroustrup.com/C++11FAQ.html#for
    for( double& sales : cust.sales_history ) stm >> sales ; // line #2

    return stm >> cust.units_purchased ; // line #3
}

// print info about one customer (format similar to the layout of the input data)
std::ostream& print_cust( std::ostream& stm, const customer& cust )
{
    stm << cust.first_name << ' ' << cust.last_name << ' ' << cust.state << '\n' ; // line #1

    for( double sales : cust.sales_history ) stm << sales << ' ' ; // line #2
    stm << '\n' ;

    return stm << cust.units_purchased << '\n' ; // line #3
}

// print info about n customers
std::ostream& print_cust( std::ostream& stm, const customer cust[], int n )
{
    for( int i = 0 ; i < n ; ++i )
    {
        print_cust( stm, cust[i] ) ;
        stm << '\n' ;
    }

    return stm ;
}

int main() // minimal test driver
{
    // we use an input string stream (instead of an actual file) for testing our code
    std::istringstream file( R"(
                                    Lucky Louis NY
                                    100 50 700
                                    2000
                                    Ariel Mermaid NC
                                    250 100 80
                                    5000
                                    Marshall Mathers FL
                                    20 100 200
                                    1000
                                    John Doeson LA
                                    100 200 300
                                    5000
                                    Jane Fanner VA
                                    50 40 200
                                    1000
                                )"
                            ) ;

    const int MAX_CUST = 10 ;
    customer cust[MAX_CUST] ;

    // read the data from the file
    int num_cust = 0 ; // number of customer info actually read from the file
    while( num_cust < MAX_CUST && get_cust( file, cust[num_cust] ) ) ++num_cust ;

    // print out what was read
    print_cust( std::cout, cust, num_cust ) ;

    if(std::cout) std::cout << "\n*** TO DO: verify that the data printed out is correct ***\n" ;

    // TO DO: rest of program (sort in varoius ways and and print etc.)
}

http://coliru.stacked-crooked.com/a/1f2b56695b711638
@JLBorges, your code is much more elegant than the brute force method I had in mind, still using a std::stringstream. Thanks for posting it. I learned from it.
Last edited on
In production code, where robust input error handling would be required, we would need to read and validate the data line by line (typically using the regex library). The code I posted is simpler only because it assumes that this is a beginner class room exercise, and we may assume that the input data is always well formed.
I wasn't even thinking about the production code aspect for error checking. I was simply marveling the use of a string stream to simulate file input, as well as how you handle filling your struct data members.

I'm a self-taught hobbyist programmer, still learning; you clearly have lots of experience in building real world code. And it shows with your solution.
Start by writing two functions (or methods). One function reads a single customer from a stream. The other writes a single customer to a stream.

Create a main() program that reads the first customer from your data file and writes the customer's data to cout.

It's extremely important to get this part right and do it first. After all, if your input and/or output functions are wrong, the output will be garbage and you won't know where to look to find the bug.

Next, change main() to read all the customers and write them all out. The main point of this part is to make sure you can read all the customers in the file.

Once you have these two simple functions, the rest of the program practically writes itself! For example:
void print_cust(customer custs, int size) {
// print the header
for (unsigned i=0; i<size; ++i) {
custs[i].write(cout); // assumes that your "output" routine above is customer::write(ostream &)
}
}
Thank you for your code. Is there anyway you can help me fix mine to do what I need it to do? Don't I require #include <iomanip> in order to format it into a table?

My array should be 10 even though my output will only include 5 customers.

@JLBorges I found your code a little overwhelming because it seems more advanced than what I am used to so is it possible to help me with the code I initially posted?
Last edited on
Start small. Here is a program that's intended to read one customer and print it out. Add code where I've written "WRITE YOUR CODE HERE" and see if you can make it work.

As I said before, once you have these two functions, the rest of the code is pretty easy.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>

using namespace std;

class customer
{
public:
    string first;
    string last;
    string state;
    double sHistory[3];		// Sales history for three years.
    double totalSales;		// Total sales (adding all three years together)
    int purchaseUnits;
};

void printcust(customer[], int);
void sortname(customer[], int);
void sortsales(customer[], int);

// functions not required, but helpful

// Print a single customer in tabular form
void printOneCust(customer & cust, ostream &strm);

// Read one customer from strm into cust
void readOneCust(customer &cust, istream &strm);

int
main()
{
    fstream infile;
    customer cust;
    
    infile.open("data.txt");
    readOneCust(cust, infile);
    printOneCust(cust, cout);
}


// Read one customer from strm into cust
void readOneCust(customer &cust, istream &strm)
{
    // WRITE YOUR CODE HERE
}


// Print a single customer in tabular form
void printOneCust(customer & cust, ostream &strm)
{
    // WRITE YOUR CODE HERE
}



Here is my modified code. The execution won't run just has a blank screen. No timeout or anything. Any ideas as to why?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

class customer{
      public:
      string first;
      string last;
      string state;
      double sHistory[3]; // Sales history for three years.
      double totalSales; // Total sales (adding all three years together)
      int purchaseUnits;
      };
void printcust(customer[], int);
void sortname(customer[], int);
void sortsales(customer[], int);



int main () 
{
		
	fstream infile;
	customer cust; 
	customer custarray[10];
	
	infile.open("data.txt");
	int i = 0;
	
	while(infile);
	{
		infile >> custarray[i].first;
		infile >> custarray[i].last;
		infile >> custarray[i].state;
		infile >> custarray[i].sHistory[0];
		infile >> custarray[i].sHistory[1];
		infile >> custarray[i].sHistory[2];
		infile >> custarray[i].purchaseUnits;
		
	custarray[i].totalSales = custarray[i].sHistory[0] + custarray[i].sHistory[1] + custarray[i].sHistory[2];
	i++;
	}
	
	i = i - 1;
	
	for(int a = 0; a < 1; a++)
	{
		cout << custarray[a].first << '\t' << custarray[a].last << '\t' << custarray[a].state << '\t';
		cout << custarray[a].sHistory[0] << " " << custarray[a].sHistory[1] << " " << custarray[a].sHistory[2];
		cout << '\t' << custarray[a].purchaseUnits << '\t' << custarray[a].totalSales;
		cout << endl << endl; 
	}

}
Remove the ; from line 34.
I removed it from line 33 because I wasn't sure if you made a mistake. It ran only one line from the data text file. How do I get it to read all names from the data text file and sort it by last name, alphabetically?
> while(infile);

That ; at the end means "do nothing"


> Any ideas as to why?
Yes, you ignored the previous advice of start small, compile and test often.

You've obviously written the whole thing (again) in one go, laboured to make it compile and now you're wondering why it doesn't work (again).

You need to figure out what your own "lines of code between tests" limit is. Because it sure isn't anywhere near 50.

Start SMALL DAMMIT!
1
2
3
4
5
6
int main ( ) {
    infile.open("data.txt");
    customer cust; 
    infile >> cust.first;
    cout << "Cust name=" << cust.first << endl;
}

Make sure you're happy, then progress.


Read the rest of one record.
1
2
3
4
5
6
7
8
9
10
11
12
13
int main ( ) {
    infile.open("data.txt");
    customer cust; 
    infile >> cust.first;
    infile >> cust.last;
    infile >> cust.state;
    infile >> cust.sHistory[0];
    infile >> cust.sHistory[1];
    infile >> cust.sHistory[2];
    infile >> cust.purchaseUnits;
    cout << "Cust name=" << cust.first << endl;
    cout << "Cust purchaseUnits=" << cust.purchaseUnits << endl;
}

Make sure you're happy, then progress.


Then you try making it an array.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main ( ) {
    infile.open("data.txt");
    customer cust[10];
    int i = 0;
    infile >> cust[i].first;
    infile >> cust[i].last;
    infile >> cust[i].state;
    infile >> cust[i].sHistory[0];
    infile >> cust[i].sHistory[1];
    infile >> cust[i].sHistory[2];
    infile >> cust[i].purchaseUnits;
    cout << "Cust name=" << cust[i].first << endl;
    cout << "Cust purchaseUnits=" << cust[i].purchaseUnits << endl;
}

Make sure you're happy, then progress.


Now you try making a loop out of it - including YOUR MISTAKE.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main ( ) {
    infile.open("data.txt");
    customer cust[10];
    int i = 0;
    while ( infile );  // OOPS!!!!!
    {
        infile >> cust[i].first;
        infile >> cust[i].last;
        infile >> cust[i].state;
        infile >> cust[i].sHistory[0];
        infile >> cust[i].sHistory[1];
        infile >> cust[i].sHistory[2];
        infile >> cust[i].purchaseUnits;
        cout << "Cust name=" << cust[i].first << endl;
        cout << "Cust purchaseUnits=" << cust[i].purchaseUnits << endl;
        i++;
    }
}

Between working and NOT working, you added exactly 4 lines of code.

Now thinking about 4 lines (well two if you discount the braces) is going to give you a much better chance at diagnosis than 50.

@Salem C - everyone makes mistakes so no need to patronize me for trying to complete an assignment.

I am NOT a professional coder. I am a STUDENT trying to learn. I've never even heard of infile before this project.

I thought this forum was to get advice and help not a lecture. Excuse me for having two jobs while trying to get a degree. And I actually did remove the semicolon after declaring the while loop.

I'll just wait for someone that is willing to explain and help rather than get upset that I don't know what I am doing.
Despite salem c's getting frustrated at you, his (and dhayden's) advice is actually sound, especially if you're overworked: whenever possible, keep the changes to your code between tests small, so that when something explodes, you have a better idea of what caused it to explode.

Another note: everything between lines 48 and 56 should probably go in your printcust function. I see you've already declared it, now you just need to implement it outside of main():
1
2
3
void printcust(customer cust[], int size) {
	//TODO: Your code here.
}

The loop condition will need to be changed to use size, but otherwise it shouldn't need too many changes.

Also, you asked about how to sort your list. Did they specify what algorithm you're supposed to use? If not, are you allowed to use std::sort, found in the <algorithm> library?

-Albatross
Pages: 12