Matrix server printing garbage values

Hi, I'm having an issue compiling my program on Matrix. The issue is with the goodType variable which is a private data member of the Good class. In visual studio, everything is printing correcttly : when I print out the the Good object it is displaying the GoodType as 'N' or 'P'. However in Matrix it is either printing out a blank or a garbage value. Here is the code :
Good.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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
[code]
 #include <iostream>
#include "Error.h"
#include "iGood.h"

namespace aid {
	const int max_sku_length = 7;// Max length for good's sku
	const int max_name_length = 75;// Max length for a good's name
	const int max_unit_length = 10;// max length for a good's description
	const double tax_rate = 0.13; // Tax rate for taxable goods

	class Good : public iGood {
		char goodType;
		char goodSku[max_sku_length + 1];
		char goodDesc[max_unit_length + 1];
		char* goodName;
		int qtyOnHand;
		int qty_needed;
		double iPrice; // Initial price of a good before tax
		bool taxable;
		Error error;
	protected:
		void name(const char*);
		const char* name() const;
		const char* sku() const;
		const char* unit() const;
		bool taxed() const;
		double itemPrice() const;
		double itemCost() const;
		void message(const char*);
		bool isClear() const;
	public:
		Good(char g_type = 'N');
		Good(const char* sku, const char* name, const char* unit, int onHand = 0, bool taxed = true, double iPrice = 0, int needed = 0);
		Good(const Good&);
		Good& operator=(const Good&);
		~Good();
		std::fstream& store(std::fstream& file, bool newLine = true) const;
		std::fstream& load(std::fstream& file);
		std::ostream& write(std::ostream& os, bool linear) const;
		std::istream& read(std::istream& is);
		bool operator==(const char*) const;
		double total_cost() const;
		void quantity(int);
		bool isEmpty() const;
		int qtyNeeded() const;
		int quantity() const;
		bool operator>(const char*) const;
		bool operator>(const iGood&) const;
		int operator+=(int);
	};

	std::ostream& operator<<(std::ostream&, const iGood&);
	std::istream& operator>>(std::istream&, iGood&);
	double operator+=(double&, const iGood&);
	iGood* CreateGood();

Last edited on
Good.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
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
Good::Good(char g_type) {
		goodType = g_type;
		goodSku[0] = '\0';
		goodDesc[0] = '\0';
		goodName = nullptr;
		qtyOnHand = 0;
		qty_needed = 0;
		iPrice = 0.00;
		taxable = true;

	}
	// Creates a Good object with all provided information
	Good::Good(const char * sku, const char * t_name, const char * unit, int onHand, bool taxed, double t_iPrice, int needed) {
		name(t_name);
		strncpy(goodSku, sku, max_sku_length);
		goodSku[max_sku_length] = '\0';
		strncpy(goodDesc, unit, max_unit_length);
		goodDesc[max_unit_length] = '\0';

		qtyOnHand = onHand;
		qty_needed = needed;
		taxable = taxed;
		iPrice = t_iPrice;
	}
	// Destructor
	Good::~Good() {
		delete[] goodName;
		goodName = nullptr;
	}
Good& Good::operator=(const Good& src) {
		if (this != &src) {
			if (src.goodType != '\0') {
				goodType = src.goodType;
			}
			strncpy(goodSku, src.goodSku, max_sku_length);
			goodSku[strlen(src.goodSku)] = '\0';
			strncpy(goodDesc, src.goodDesc, max_unit_length);
			goodDesc[strlen(src.goodDesc)] = '\0';
			qtyOnHand = src.qtyOnHand;
			qty_needed = src.qty_needed;
			taxable = src.taxable;
			iPrice = src.iPrice;
			error.message(src.error.message());
			delete[] goodName;
			if (src.goodName != nullptr) {
				name(src.goodName);
			}

			else
			{
				goodName = nullptr;
			}

		}
		return *this;
	}
	// Copy Constructor
	Good::Good(const Good& src) {
		goodName = nullptr;
		*this = src;
	}
	// Inserts current object's data into an fstream object
	std::fstream& Good::store(std::fstream& file, bool newLine) const {
		file << goodType << ',' << goodSku << ',' << goodName << ',' << goodDesc << ',' << taxable
			<< ',' << iPrice << ',' << qtyOnHand << ',' << qty_needed;
		if (newLine) {
			file << endl;
		}
		return file;
	}
	// Extracts fields for a record into fstream object
	std::fstream& Good::load(std::fstream& file) {
		// Create a temporary object
		char tGoodSku[max_sku_length];
		char tGoodName[max_name_length];
		char tGoodDesc[max_unit_length];
		double tPrice;
		int tQtyHand;
		int tQtyNeeded;
		char tTax;
		bool tTaxable;
		// Extract field data into temporary object
		if (file.is_open()) {
			
			file.getline(tGoodSku, max_sku_length, ',');
			tGoodSku[strlen(tGoodSku)] = '\0';

			file.getline(tGoodName, max_name_length, ',');
			tGoodName[strlen(tGoodName)] = '\0';

			file.getline(tGoodDesc, max_unit_length, ',');
			tGoodDesc[strlen(tGoodDesc)] = '\0';
			file >> tTax;

			if (tTax == '1') {
				tTaxable = true;
			}
			else {
				tTaxable = false;
			}
			file.ignore();
			file >> tPrice;
			file.ignore();
			file >> tQtyHand;
			file.ignore();
			file >> tQtyNeeded;
			char saveType = goodType;
			*this = Good(tGoodSku,tGoodName,tGoodDesc,tQtyHand,tTaxable,tPrice,tQtyNeeded); // Assign to current object
			goodType = saveType;
		}
		
		return file;
	}
	// Inserts current object's data into ostream in desired format
	std::ostream& Good::write(std::ostream& os, bool linear) const {
		if (isClear() && !isEmpty()) {
			if (linear) {
				os << setw(max_sku_length) << left << setfill(' ') << sku() << '|';
				os << setw(20) << left << name() << '|';
				os << setw(7) << right << fixed << setprecision(2) << itemCost() << '|';
				os << setw(4) << right << quantity() << '|';
				os << setw(10) << left << unit() << '|';
				os << setw(4) << right << qtyNeeded() << '|';
			}
			else {
				os << " Sku: " << goodSku << endl;
				os << " Name (no spaces): " << goodName << endl;
				os << " Price: " << iPrice << endl;
				if (taxable) {
					os << " Price after tax: " << itemCost() << endl;
				}
				else {
					os << " Price after tax: N/A" << endl;
				}
				os << " Quantity on hand: " << qtyOnHand << ' ' << unit() << endl;
				os << " Quantity needed: " << qty_needed << endl;
			}
		}
		if (!isClear()) {
			os << error.message();
		}
		return os;
	}
	// Extracts data fields for the current object based on user input
	std::istream& Good::read(std::istream& is) {
		// Store data in temporary variables
		char t_goodSku[max_sku_length + 1];
		char *t_goodName = new char[max_name_length + 1];
		char t_goodDesc[max_unit_length + 1];
		int t_qtyOnHand;
		int t_qty_needed;
		double t_price;
		char taxed;
		bool t_taxable;
		//Error error;

		// Prompt user for data, store into istream object
		cout << " Sku: ";
		is >> t_goodSku;
		cout << " Name (no spaces): ";
		is >> t_goodName;
		cout << " Unit: ";
		is >> t_goodDesc;
		cout << " Taxed? (y/n): ";
		is >> taxed;
		if (taxed == 'Y' || taxed == 'y') {
			t_taxable = true;
		}
		else if (taxed == 'N' || taxed == 'n') {
			t_taxable = false;
		}
		// If input is invalid, set istream failbit and display error message
		else {
			is.setstate(std::ios::failbit);
			error.message("Only (Y)es or (N)o are acceptable");
		}
		if (!is.fail()) {
			cout << " Price: ";
			is >> t_price;
			if (is.fail()) {
				error.message("Invalid Price Entry");
				delete[] t_goodName;
				return is;
			}
		}
		if (!is.fail()) {
			cout << " Quantity on hand: ";
			is >> t_qtyOnHand;
			if (is.fail()) {
				error.message("Invalid Quantity Entry");
				delete[] t_goodName;
				return is;
			}
		}
		if (!is.fail()) {
			cout << " Quantity needed: ";
			is >> t_qty_needed;
			if (is.fail()) {
				error.message("Invalid Quantity Needed Entry");
				delete[] t_goodName;
				return is;
			}
		}
		// If all input is valid, create temporary object with given values, copy assign to current object
		if (!is.fail()) {
			Good temp = Good(t_goodSku, t_goodName, t_goodDesc, t_qtyOnHand, t_taxable, t_price, t_qty_needed);
			*this = temp;
			
		}
		delete[] t_goodName;
		t_goodName = nullptr;
		return is;
	}
Tester (main) Where error occurs:
1
2
3
4
5
6
7
8
9
10
cout << "----Storage and loading test, the output of the Program and yours must match:" << endl;
		iGood* tempGood = CreateGood();
		good->store(goodsFile);
		good->store(goodsFile);
		goodsFile.close();
		cout << "--Store Good, program: " << endl
			<< "N,1234,box,kg,1,123.45,1,5" << endl
			<< "N,1234,box,kg,1,123.45,1,5" << endl;
		cout << "--Store Good, yours: " << endl;
		dumpFile("good.txt");
1
2
3
	char t_goodSku[max_sku_length + 1];
		char *t_goodName = new char[max_name_length + 1];
		char t_goodDesc[max_unit_length + 1];

I would suggest you ditch all this roll-your-own string memory management (some chaotic mix of arrays, allocated pointers, and raw pointers to external data), and use a std::string for each string you want to store.

Yes, I understand it's chaotic, it's for a school assignment however and we have to store each resource in a specified way
Without seeing iGood, who knows.

1
2
3
4
5
// Copy Constructor
	Good::Good(const Good& src) {
		goodName = nullptr;
		*this = src;
	}

This is a disaster!
1. The first assignment leaks the memory that goodName used to point to.
2. The second assignment makes this.goodName and src.goodName point to the SAME string. If one instance deletes the string, the other instance is royally screwed.
Look up "c++ deep copy"

Naked pointers inside classes need special attention at every step of the way.

Last edited on
iGood.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
#include <iostream>
#include <fstream>

namespace aid {
	class iGood {
	public:
		virtual ~iGood() {};
		virtual std::fstream& store(std::fstream& file, bool newLine = true) const = 0;
		virtual std::fstream& load(std::fstream& file) = 0;
		virtual std::ostream& write(std::ostream& os, bool linear) const = 0;
		virtual std::istream& read(std::istream& is) = 0;
		virtual bool operator==(const char*) const = 0;
		virtual double total_cost() const = 0;
		virtual const char* name() const = 0;
		virtual void quantity(int) = 0;
		virtual int qtyNeeded() const = 0;
		virtual int quantity() const = 0;
		virtual int operator+=(int) = 0;
		virtual bool operator>(const iGood&) const = 0;

	};

	std::ostream& operator<<(std::ostream&, const iGood&);
	std::istream& operator>>(std::istream&, iGood&);
	double operator+=(double&, const iGood&);
	iGood*  CreateGood();
	iGood* CreatePerishable();

}
The copy constructor is calling the overloaded assignment operator, which is calling a special function to copy the goodName dynamic resource. There is no issue with the GoodName resource, it is generating the correct output.
Topic archived. No new replies allowed.