How to properly read data from textfile into an array of objects?

Just as the title states. I don't know where I am going wrong. I thought my thought process and code would work but it doesn't. I used the debugger and I checked the stks array at each index and it is just initialized to 0 for numerical values or initialized to " " for string values. Someone please steer me in the right direction. I also have to read from the text file until the end of the file or maxSize has been reached, whichever comes first. I am also allowed to set the 'int ReadStkData(Stock stks[], int maxSize)' function as a friend to access the private variables of the class.

*Obviously this is still a work in progress (hence the missing code and member functions)*

I am reading from this text file...
StockData.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
RDEN Elizabeth Arden Inc# 40 25 13.25 9.8
AVP Avon Products Inc# 40 12 5.0 5.03
COH Coach Inc# 40 16 39.0 41.2
BAC Bank of America Corp# 30 23 20.5 14.25
WFC Wells Fargo & Co# 30 9 48.2 48.21
V Visa# 30 12 83.4 80.1
JNJ Johnson & Johnson# 20 3 105.2 109.82
LLY Eli Lilly and Company# 20 5 73.2 75.19
RPTP Raptor Pharmaceutical Corp# 20 18 5.6 5.64
CA CA Inc# 10 10 30.0 30.05
SYMC Symantec Corp# 10 7 20.8 17.9
TWTR Twitter Inc# 10 12 15.25 17.7
EIX Edison International# 50 2 71.03 71.0
HE Hawaiian Electric Industries Inc# 50 22 25.5 32.60
POR Portland General Electric# 50 9 43.6 39.54 


Stock.h
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
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
using namespace std;

#ifndef STOCK_H
#define STOCK_H

class Stock
{
private:
	string TradingSymbol;
	string CompanyName;
	enum Sector { Technology, Health, Financial, Consumer_Goods, Utilities };
	int NUMofShares;
	double CurrentPrice;
	double PurchasePrice;
	double CurrentValue; //used with CurrValue (public method)

public:
	//default constructor
	Stock();
	
	//mutator functions declared in-line
	void setTradingSymbol(string trade) { TradingSymbol = trade; }
	void setCompanyName(string compName) {CompanyName = compName; }
	void setSector(int);
	void setNUMofShares(int shares) { NUMofShares = shares; }
	void setCurrentPrice(double currentPr) { CurrentPrice = currentPr; }
	void setPurchasePrice(double purchPr) { PurchasePrice = purchPr; }


	//friend function that reads stock data from file
	friend int ReadStkData(Stock stks[], int maxSize);

};

#endif 


StockMain.cpp
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 "Stock.h"

int main()
{
	const int MAX_SIZE = 25;
	Stock StockInfo[MAX_SIZE];
	cout << ReadStkData(StockInfo, MAX_SIZE);
	return 0;
}

int ReadStkData(Stock stks[], int maxSize)
{
	string filename, Trade = " ", Company = " ";
	int Shares = 0;
	double pPrice = 0, cPrice = 0;;
	fstream inFile;
	int elementCounter = 0;
	cout << "User, please enter the name of the file to be read: ";
	cin >> filename; //correct filename for testing sample file is StockData.txt

	inFile.open(filename, ios::in);

	// this for loop must read until the end of the file or maxSize has been reached, whichever comes first
	for (int x = 0; x < maxSize; x++)
	{
		getline(inFile, Trade, ' ');
		stks[x].setTradingSymbol(Trade);
		getline(inFile, Company, '#');
		stks[x].setCompanyName(Company);	
		inFile >> Shares;
		stks[x].setNUMofShares(Shares);
		inFile >> pPrice;
		stks[x].setPurchasePrice(pPrice);
		inFile >> cPrice;
		stks[x].setCurrentPrice(cPrice);
		elementCounter++;
	}

	inFile.close();

	return elementCounter;
}


Stock.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "Stock.h"
using namespace std;

Stock::Stock()
{
	TradingSymbol = "AAA";
	CompanyName = "Company Not Found";
	Sector sctr = static_cast <Sector>(0);
	NUMofShares = 0;
	PurchasePrice = 0.0;
	CurrentPrice = 0.0;
	CurrentValue = 0.0;
}

void Stock::setSector(int)
{
}
Last edited on
The first problem is mixing >> (line 35) and getline(...) (line 26). See Notes:

http://en.cppreference.com/w/cpp/string/basic_string/getline

The second problem is that you don't take eof into account. With a bit reorganization:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
	for (int x = 0; x < maxSize; x++)
	{
		getline(inFile, Trade, ' ');
		getline(inFile, Company, '#');
		inFile >> Shares;
		inFile >> pPrice;
		inFile >> cPrice;

if(inFile) // Note: the stream returns true if reading was successful
{
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

		stks[x].setTradingSymbol(Trade);
		stks[x].setCompanyName(Company);	
		stks[x].setNUMofShares(Shares);
		stks[x].setPurchasePrice(pPrice);
		stks[x].setCurrentPrice(cPrice);
		elementCounter++;
}
else
  break;
	}
You may use elementCounter in place of x.
coder777,

I tried that. It seems as if the file keeps failing now. I am on a different computer than the one I used last night. I don't know if that is causing it.

Here is the updated StockMain.cpp file

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
#include "Stock.h"

int main()
{
	const int MAX_SIZE = 25;
	Stock StockInfo[MAX_SIZE];
	cout << ReadStkData(StockInfo, MAX_SIZE);
	return 0;
}

int ReadStkData(Stock stks[], int maxSize)
{
	string filename, Trade = " ", Company = " ";
	int Shares = 0;
	double pPrice = 0, cPrice = 0;;
	fstream inFile;
	int indexTotal = 0; //used to access elements of stks array, also stores the total # of elements in the array
	cout << "User, please enter the name of the file to be read: ";
	cin >> filename; //correct filename for testing sample file is StockData.txt

	inFile.open(filename, ios::in);

	if (inFile.fail()) {
		cout << "Error! Exiting!" << endl;
		exit(-1);
	}
	for (indexTotal; indexTotal < maxSize; indexTotal++)
	{
		getline(inFile, Trade, ' ');
		getline(inFile, Company, '#');
		inFile >> Shares;
		inFile >> pPrice;
		inFile >> cPrice;

		if (inFile) // Note: the stream returns true if reading was successful
		{
			inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

			stks[indexTotal].setTradingSymbol(Trade);
			stks[indexTotal].setCompanyName(Company);
			stks[indexTotal].setNUMofShares(Shares);
			stks[indexTotal].setPurchasePrice(pPrice);
			stks[indexTotal].setCurrentPrice(cPrice);
			indexTotal++;
		}
		else
			break;
	}

	inFile.close();

	return indexTotal;
}
Last edited on
Hello MisterTams,

For the most part the program works, but needs a few tweaks.

Starting with the data file I add an extra number after the "#". Could just as easily put that at the end of the line also. More on this later.

In "Stock.h" after the "enum" I added "Sector sctr;" because there was no place to store this number. In "Stock.cpp" you started a setter function for this, but did not finish it. I would guess you did not know where to store it. I added two "Get" functions to retrieve information from the private variables. The use will show up later in main.

"main" is fine although I adjusted this way for testing:

1
2
3
4
5
6
7
8
9
std::cout << " " << ReadStkData(StockInfo, MAX_SIZE) << " Items read." << std::endl;

std::cout << std::endl;  //  Not necessary. Used as a break point for testing

for (size_t lp = 0; lp < MAX_SIZE; lp++)
{
	std::cout << std::setw(3) << lp + 1 << " " <<StockInfo[lp].GetCompanyName() << ", "
			    << StockInfo[lp].GetSector() << std::endl;
}


The for loop could easily be put in a Display function.

I would also suggest changing the array to a "std::vector". It is more useful and you will not have to change "MAX_SIZE" as the data file grows.

In the "ReadStkData" function I added
1
2
inFile >> sctr;
stks[x].setSector(sctr);

and I changed the for loop to while (std::getline(inFile, Trade, ' ')) this way when end of file is reached, "inFile" will fail and then the while loop will fail. As coder777 suggested it would be easier to change "elementCounter" to "x". I found this t be the simplest way to fix what you have. Another advantage to this way is that unused elements of the array will be left alone leaving them as they were first initialized.

The program runs as you first posted it, but the for loop in the "ReadStkData" function will fill the array elements 16 - 24 with the same data as element 15. Not what you want.

If anything is unclear let me know.

Hope that helps,

Andy
Andy,

Thanks for your input. Some of the things that I am doing in my code are out of requirement as per the class I am in. For example, I would love to use a vector but I have to use an array.
I have to go into work, but I will check back tonight and try to update my code with the advice you have given.

Thanks,
MisterTams
Remove line 44. It is double increment.
Hello MisterTams,

No problem, my changes are based on using the array. Just thought the vector would be easier.

Andy
Last edited on
Okay, I'm still at work but I found some time to update my code.

So here is StockMain.cpp

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
#include "Stock.h"

int main()
{
	const int MAX_SIZE = 25;
	Stock StockInfo[MAX_SIZE];
	cout << "\nNumber of 'Stock' Objects in StockInfo Array: " << ReadStkData(StockInfo, MAX_SIZE) << endl;
	return 0;
}

int ReadStkData(Stock stks[], int maxSize)
{
	string filename, Trade = " ", Company = " ";
	int Shares = 0, sctr = 0;
	double pPrice = 0, cPrice = 0;;
	fstream inFile;
	int indexTotal = 0;
	cout << "User, please enter the name of the file to be read: ";
	cin >> filename; //correct filename for testing sample file is StockData.txt

	inFile.open(filename, ios::in);

	if (inFile.fail()){
		cout << "Error opening file! Exiting Program!" << endl;
		exit(-1);
	}
	// this for loop must read until the end of the file or maxSize has been reached, whichever comes first
	//for (int x = 0; x < maxSize; x++)
	while (getline(inFile, Trade, ' '))
	{
		stks[indexTotal].setTradingSymbol(Trade);
		getline(inFile, Company, '#');
		stks[indexTotal].setCompanyName(Company);
		inFile >> sctr;
		stks[indexTotal].setSector(sctr);
		inFile >> Shares;
		stks[indexTotal].setNUMofShares(Shares);
		inFile >> pPrice;
		stks[indexTotal].setPurchasePrice(pPrice);
		inFile >> cPrice;
		stks[indexTotal].setCurrentPrice(cPrice);
		inFile.ignore(100000, '\n');
		indexTotal++;
		
		if (inFile.eof())
			break;
	}

	inFile.close();

	return indexTotal;
}


Stock.h is now updated to..

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 <fstream>
using namespace std;

#ifndef STOCK_H
#define STOCK_H

class Stock
{
private:
	string TradingSymbol;
	string CompanyName;
	static enum Sector { Technology, Health, Financial, Consumer_Goods, Utilities }; //static
	Sector sctr;
	int NUMofShares;
	double PurchasePrice;
	double CurrentPrice;
	double CurrentValue; //used with CurrValue (public method)

public:
	//default constructor
	Stock();
	
	//public static named constant for tax gain
	static const double TaxOnGain; 
	
	//mutator functions declared in-line
	void setTradingSymbol(string trade) { TradingSymbol = trade; }
	void setCompanyName(string compName) {CompanyName = compName; }
	void setSector(int);
	void setNUMofShares(int shares) { NUMofShares = shares; }
	void setCurrentPrice(double currentPr) { CurrentPrice = currentPr; }
	void setPurchasePrice(double purchPr) { PurchasePrice = purchPr; }

	//accessor functions
	string getTradingSymbol() const {return TradingSymbol;}
	string getCompanyName() const {return CompanyName;}
	string getSector() const;
	int getNUMofShares() const {return NUMofShares;}
	double getPurchasePrice() const {return PurchasePrice;}
	double getCurrentPrice() const {return CurrentPrice;}
	
	// other public methods
	double CurrValue() const;
	string CurrStatus() const; // must return enumerated type of GAIN, LOSS, or BREAKEVEN ????
	double GainAmt() const;
	double TaxGainAmt() const;

	//friend function that reads stock data from file
	friend int ReadStkData(Stock stks[], int maxSize);
};



#endif  


Stock.cpp is now...

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
#include "Stock.h"
using namespace std;

Stock::Stock()
{
	TradingSymbol = "AAA";
	CompanyName = "Company Not Found";
	Sector sctr = static_cast <Sector>(0);
	NUMofShares = 0;
	PurchasePrice = 0.0;
	CurrentPrice = 0.0;
	CurrentValue = 0.0;
}

void Stock::setSector(int sctrInt)
{
	if (sctrInt == 10)
		sctr = static_cast <Sector> (0);
	else if (sctrInt == 20)
		sctr = static_cast <Sector> (1);
	else if (sctrInt == 30)
		sctr = static_cast <Sector> (2);
	else if (sctrInt == 40)
		sctr = static_cast <Sector> (3);
}

string Stock::getSector() const
{
	if (sctr == Technology)
		return "Technology";
	else if (sctr == Health)
		return "Health";
	else if (sctr == Financial)
		return "Financial";
	else if (sctr == Consumer_Goods)
		return "Consumer Goods";
	else if (sctr == Utilities)
		return "Utilities";
}

//public static named constant
//must be initialized outside of class definition
//therefore it's in the implementation file for class
const double Stock::TaxOnGain = 0.15; 


I have alot more work to do still.

Also directly addressing you Handy Andy,
I used your method of looping and reading the data with a while loop.
It seems to work really well.

I have to read until the end of file is reached or the index of maxSize is reached (maxSize = 25).
So I may have to modify the code some more when reading the data from the file, but I really like the while loop method.
Hello MisterTams,

In StockMain.cpp you can remove lines 45 and 46 as the while condition takes care of the "eof" checking. When the getline tries to read past "eof" "inFile" fails making the result of the while condition false so it fails.

In Stock.cpp for line 8 of the constructor all you need is sctr = static_cast <Sector>(0);. You do not need to give "sctr" a type here because it is already defined "Stock.h". In the "Stock::getSector()" function I used a switch but the if statements work just fine.

At first look the "Stock::setSector()" function appears to be a bit much for something that should be simple.

At first glance the "Stock.h" is looking better and I do not see any problems as of now. I will have to look at it better tomorrow.

Hope that helps,

Andy
Handy Andy,

Thanks for the continuous help and considerations that you are offering!

Does this look better for Stock::setSector() and getSector() member functions?

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
void Stock::setSector(int sctrInt)
{
	if (sctrInt == 10)
		sctr = Technology;
	else if (sctrInt == 20)
		sctr = Health;
	else if (sctrInt == 30)
		sctr = Financial;
	else if (sctrInt == 40)
		sctr = Consumer_Goods;
	else if (sctrInt == 50)
		sctr = Utilities;
}

string Stock::getSector() const
{
	if (sctr == Technology)
		return "Technology";
	else if (sctr == Health)
		return "Health";
	else if (sctr == Financial)
		return "Financial";
	else if (sctr == Consumer_Goods)
		return "Consumer Goods";
	else if (sctr == Utilities)
		return "Utilities";
}
Hello MisterTams,

At first look everything looks like it should work.

I think you are going a bit overboard with the set function. Starting with the input file the number added for the "Sector" should match the "enum Sector" names, i.e., a value of 1 to 4. Then the SetSector function would only need to be:

1
2
3
4
void Stock::setSector(int vnum)
{
	sctr = static_cast<Sector> (vnum);
}


Excuse the "vnum" as I did not put much thought into the name, not that it really matters what the name is.

In the "get" function there is nothing wrong with what you have. Although it is a good palce for a switch. If you are not familiar with a switch you can read up here:
http://www.cplusplus.com/doc/tutorial/control/#switch

Hope that helps,

Andy
Topic archived. No new replies allowed.