Exception thrown: read access violation

Pages: 12
So, I'm having a hell of a time with this final assignment for my c++ class. Basically I am to make an InventoryClass and a derived InventoryCostClass. Then in the main the user has to be able to update the inventory; the updates are to be stored in a binary file. That file is then used to update the array of class objects accordingly. Here's all I've got so far:
InventoryClass.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
#ifndef INVENTORYCLASS_H
#define INVENTORYCLASS_H
#include<iostream>
#include<string>
#include<iomanip>
using namespace std;
class Inventory {
protected:
	int itemID, itemQty;
	string itemDesc;
public:
	Inventory() {};
	Inventory(int id,string desc,int qty)
		{ itemID = id; itemDesc = desc; itemQty = qty; }
	void setID(int id)
		{ itemID = id; }
	void setDesc(string desc)
		{ itemDesc = desc; }
	void setQty(int qty) 
		{ itemQty = qty; }
	int getID() const 
		{ return itemID; }
	string getDesc() const 
		{ return itemDesc; }
	int getQty() const 
		{ return itemQty; }
	virtual void setInfo() 
		{ int id, qty;
		string desc;
		cout << "Enter ItemID: ";
		cin >> id;
		cout << "Enter ItemDescription: ";
		cin.ignore();
		getline(cin, desc);
		cout << "Enter ItemQuantity: ";
		cin >> qty;
		setID(id);
		setDesc(desc);
		setQty(qty); }
	virtual void print() 
		{ cout << setw(18) << "Item ID: " << getID() << endl;
		cout << setw(18) << "Item Description: " << getDesc() << endl;
		cout << setw(18) << "Item Quantity: " << getQty() << endl; }
};
#endif 


Last edited on
Then the ""CostClass.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
57
58
59
60
61
62
63
64
65
#ifndef INVENTORYCOSTCLASS_H
#define INVENTORYCOSTCLASS_H
#include"InventoryClass.h"

class InventoryCost :public Inventory {
private:
	double wCost, rCost;
	int month, day, year;
public:
	InventoryCost() {};
	InventoryCost(int id, string desc, int qty,
		double wc,double rc,int m,int d, int y) 
		: Inventory(id, desc, qty)
		{ wCost = wc; rCost = rc; month = m; day = d; year = y; }
	void setWCost(double wc) 
		{ wCost = wc; }
	void setRCost(double rc) 
		{ rCost = rc; }
	void setMonth(int m) 
		{ month = m; }
	void setDay(int d)
		{ day = d; }
	void setYear(int y)		
		{ year = y; }
	double getWCost() const
		{ return wCost; }
	double getRCost() const
		{ return rCost; }
	int getDay() const
		{ return day; }
	int getMonth() const
		{ return month; }
	int getYear() const
		{ return year; }
	void setInfo() 
		{ double wc, rc;
		int m, d, y;
		Inventory::setInfo();
		cin.ignore();
		cout << "Enter Wholesale Cost: $";
		cin >> wc;
		cout << "Enter Retail Cost: $";
		cin >> rc;
		cout << "Enter Inventory Update date in mm/dd/yyyy format\n"
			<< "Month: ";
		cin >> m;
		cout << "Day: ";
		cin >> d;
		cout << "Year: ";
		cin >> y;
		setWCost(wc);
		setRCost(rc);
		setMonth(m);
		setDay(d);
		setYear(y);	}
	void print()
		{ Inventory::print();
		cout << fixed << showpoint << setprecision(2);
		cout << setw(19) << "Wholesale Cost: $" << getWCost() << endl;
		cout << setw(19) << "Retail Cost: $" << getRCost() << endl;
		cout << setw(18) << "Date Modified: " << getMonth() << "/"
			<< getDay() << "/" << getYear() << endl << endl; }
};

#endif 



and finally the main.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
#include "InventoryClass.h"
#include "InventoryCostClass.h"
#include<iostream>
#include<fstream>
#include<algorithm>
using namespace std;

const int SIZE = 6;

struct Edit {
	int itID;
	char code[3], edit[51];
};


int menu();
void displayInv(InventoryCost[]);
void createFile(fstream&, string);
void printFile(fstream&, string, InventoryCost[]);

int main() {

	InventoryCost itemInv[SIZE] = 
	  { InventoryCost(209875, "Global - Designed Wrench : catalog 145HN - 89", 1056,
		  14.67, 23.99, 10, 13, 2014),
	    InventoryCost(176524, "Steeheel Chainsaw - 120 H - P: catalog 133NM - 65", 2654,
		  234.67, 299.99, 10, 13, 2014),
	    InventoryCost(340965, "Plurers Pliers with Sure - Grip: catalog 764TW - 12", 1043,
		  11.45, 19.98, 10, 13, 2014),
		InventoryCost(453285, "Rapid Recoil Hand Tape Measure : catalog 127UY - 32", 3316, 
		  8.56, 15.99, 10, 13, 2014),
		InventoryCost(893167, "Steady Built Steel Saw Horses : catalog 564HG - 34", 764, 
		  45.54, 79.99, 10, 13, 2014),
		InventoryCost(597895, "Big Boy Bib Overalls - L - XL - XXL: catalog 278LG - 45", 5032, 
		  19.76, 39.99, 10, 13, 2014) };
	int ch = 0;
	fstream file;
	string filename, name, extension = ".dat";

	cout << " *Choose a name for the update file: ";
	cin >> name;
	filename = name + extension;
	do {
		ch = menu();
		if (ch != 6) {
			switch (ch)
			{
			case 1:
				displayInv(itemInv);
				break;
			case 2:
				createFile(file, filename); 
				break;
			case 3:
				printFile(file, filename, itemInv);
				break;
			case 4: 
				break;
			case 5:
				break;
			}
		}
	} while (ch != 6);

	system("pause");
	return 0;
}

int menu() {
	int choice;
	cout << "**********************************\n"
		<< "*________MENOCU TOOL SHOP________*\n"
		<< "**********************************\n"
		<< "*  1. Display Inventory          *\n"
		<< "*  2. Create a Transaction File  *\n"
		<< "*  3. Update Inventory           *\n"
		<< "*  4. Display Updated Inventory  *\n"
		<< "*  5. Compute Profit Projection  *\n"
		<< "*  6. EXIT                       *\n"
		<< "**********************************\n"
		<< " Menu Choice: ";
	cin >> choice;
	return choice;
}

void displayInv(InventoryCost itemInv[SIZE]) {
	for (int i = 0; i < SIZE; i++) {
		cout << "Item #" << i+1 << ": " << endl;
		itemInv[i].print();
	}
}

void createFile(fstream &file, string filename) {
	Edit ed;
	int num;
	file.open(filename.c_str(), ios::out | ios::binary);
	if (!file) {
		cout << "ERROR opening file!\n";
	}
	cout << "How many records to ammend: ";
	cin >> num;
	cout << "Her are the Transaction Codes: \n"
		<< "\tAI: Add to Inventory\n"
		<< "\tRI: Reduce from Inventory\n"
		<< "\tCW: Change Wholesale Cost\n"
		<< "\tCR: Change Retail Price\n"
		<< "\tCD: Change Description\n\n";
	for (int i = 0; i < num; i++) {
		cout << "Enter the ItemID #: ";
		cin >> ed.itID;
		cout << "Enter the Transaction Code: ";
		cin.ignore();
		cin.getline(ed.code, 3);
		cout << "Enter New Data: ";
		cin.getline(ed.edit, 51);
		file.write(reinterpret_cast<char *>(&ed), sizeof(ed));
	}
	file.close();
}
 
void printFile(fstream &file, string filename, InventoryCost inv[SIZE]) {
	Edit it;
	InventoryCost *ptrI[SIZE];
	ptrI[SIZE] = &inv[SIZE];
	file.open(filename.c_str(), ios::in | ios::binary);
	if (!file) {
		cout << "ERROR opening file!\n";
	}
	file.clear();
	file.read(reinterpret_cast<char *>(&it), sizeof(it));
	while (!file.eof()) {
		cout << it.itID << " " << it.code << " " << it.edit << endl;
		for (int i = 0; i < SIZE; i++) {
			if (ptrI[i]->getID() == it.itID) {
				if (it.code == "AI")
					ptrI[i]->setQty(atoi(it.edit));
				else if (it.code == "RI")
					ptrI[i]->setQty(atoi(it.edit));
				else if (it.code == "CW")
					ptrI[i]->setWCost(atof(it.edit));
				else if (it.code == "CR")
					ptrI[i]->setRCost(atof(it.edit));
				else if (it.code == "CD")
					ptrI[i]->setDesc(it.edit);
				else
					cout << "Invalid Transaction Code\n";
			}
		}
		file.read(reinterpret_cast<char *>(&it), sizeof(it));
	}
	file.close();
}


The thing is the compiler doesn't show any errors, but when I run switch 3 it crashes.

> The thing is the compiler doesn't show any errors
143:25 comparison with string literal results in unspecified behaviour [-Waddress]
     else if (it.code == "CD")
you may compare `std::string' with ==
else you need `strcmp()'


> but when I run switch 3 it crashes.
provide an example input.
ptrI[SIZE] = &inv[SIZE];
This says:
ptrI[6] = &inv[6];

This is a bit of a problem, as there is no ptrI[6], there is no inv[6], and it means that prti[0] to ptrI[5] are left uninitialised, and thus filled with random data.


Also, all of these:
if (it.code == "AI")
do not do what you think they do. On the left is a pointer to a memory address, and on the right is a pointer to a different memory address. This is checking that two pointers are pointing to the exact same piece of memory. This does NOT compare the characters in the array it.code to the string AI.

Do yourself a favour; don't use char arrays.
Last edited on
Ok, so if I get rid of the char arrays and go with string data I'm guessing its a
 
strcmp(it.code, "AI");


but what about the array of class objects? I'm so confused here.
@ne55
I don't get output, I get a dialog box that pops up and says, "Exception thrown at 0x00E8C626 in Greaney_Brian_CIS1202_FinalProject.exe: 0xC0000005: Access violation reading location 0xCCCCCCD0.

If there is a handler for this exception, the program may be safely continued."
then I break.
Ok, so if I get rid of the char arrays and go with string data I'm guessing its a
strcmp(it.code, "AI");

No. The point of using strings is so that you can use ==. If it.code is a string, you can compare it with it.code =="AI"

Here is strcmp: http://www.cplusplus.com/reference/cstring/strcmp/
See how it is meant for C style string (i.e. char arrays)? It is not meant for proper C++ string objects.


If you have an array of objects, and you want another array of objects to contain copies of that first set of objects, it is done like this:
1
2
3
secondArray[0] = firstArray[0];
secondArray[1] = firstArray[1];
secondArray[2] = firstArray[2];

and so on.

Note that if your array is an array of pointers, you will be creating copies of pointers. The objects that those pointers are pointing at will not be copied.


As an aside, you've done yourself no favours by choosing to use arrays. Arrays are for advanced users. Beginners should use vectors.
Last edited on
However if you go with std::string then remember you can't write() a std::string directly to a binary file.


@jlb I know that's why the char[](now string) is in a struct. that way i just reinterpret the whole thing at once.

@Moschops Really? We learned arrays way before touching on vectors. Now without sounding too 'beggy' what should I do here since I am using arrays? I originally didn't even make an array of pointers, I just used the array passed to the function from the main but VS told me i needed to use pointers. So confused...
Again, thanks for any help.
I'm not surprised. For some bizarre reason, people seem to teach arrays before vectors. It makes no sense and I can only assume they're never thought about what they're teaching.

It's unfortunate, because it's clear that how you're thinking of arrays is actually a good match for a vector. The mental model you have of an array is wrong; it's a lot closer to the correct mental model of a vector.

You've no need for an array of pointers here. Just have an array of actual objects.

The key gap in your model here is this understanding; there is (at least in any way I'd be happy explaining to a beginner) NO WAY to pass an array. There is NO WAY to copy an array. An array barely exists. It's not an object. It's some objects all next to each other in memory. Those objects exist; "array" is just a shorthand way to refer to those objects.

If you have an array, and you need another function to make use of that array, all you can do is pass a pointer to the start of the array.

If you have an array, and you want to make a copy of that array, all you can do is make a new array of the right size and copy each element of the array individually.

Any time you find yourself thinking of the array as a single object, you're thinking wrong and setting yourself up for a mistake.

Last edited on
You can't write a structure that has std::string member variables with the write() function.

You'll need to write() each individual member function, making sure you either write() the length() of the string prior to the string.c_str() or string.data(), or write a fixed number of bytes using either the string.data() or string.c_str() values.

Ok, so i write individual file.write statements for writing it in. Now that the string is in the file will my original file.read(reinterpret_cast<char *>(&it), sizeof(it)); work to fill the struct from the file for the tests?
No, you'll need to read() the individual items as well. How you read() the strings will depend on how you wrote the strings. The read() is basically the opposite of the write(). You need to read the exact number of bytes that you wrote.


Exception thrown: read access violation.
_Pnext was 0x35354945.

Unhandled exception thrown: read access violation.
_Pnext was 0x35354945.

The program '[16488] Greaney_Brian_CIS1202_FinalProject.exe' has exited with code 0 (0x0).

here's revised code:
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
#include "InventoryClass.h"
#include "InventoryCostClass.h"
#include<iostream>
#include<fstream>
#include<algorithm>
using namespace std;

const int SIZE = 6;

struct Edit {
	int itID;
	string code, edit;
};


int menu();
void displayInv(InventoryCost[]);
void createFile(fstream&, string);
void printFile(fstream&, string, InventoryCost[]);

int main() {

	InventoryCost itemInv[SIZE] = 
	  { InventoryCost(209875, "Global - Designed Wrench : catalog 145HN - 89", 1056,
		  14.67, 23.99, 10, 13, 2014),
	    InventoryCost(176524, "Steeheel Chainsaw - 120 H - P: catalog 133NM - 65", 2654,
		  234.67, 299.99, 10, 13, 2014),
	    InventoryCost(340965, "Plurers Pliers with Sure - Grip: catalog 764TW - 12", 1043,
		  11.45, 19.98, 10, 13, 2014),
		InventoryCost(453285, "Rapid Recoil Hand Tape Measure : catalog 127UY - 32", 3316, 
		  8.56, 15.99, 10, 13, 2014),
		InventoryCost(893167, "Steady Built Steel Saw Horses : catalog 564HG - 34", 764, 
		  45.54, 79.99, 10, 13, 2014),
		InventoryCost(597895, "Big Boy Bib Overalls - L - XL - XXL: catalog 278LG - 45", 5032, 
		  19.76, 39.99, 10, 13, 2014) };
	int ch = 0;
	fstream file;
	string filename, name, extension = ".dat";

	cout << " *Choose a name for the update file: ";
	cin >> name;
	filename = name + extension;
	do {
		ch = menu();
		if (ch != 6) {
			switch (ch)
			{
			case 1:
				displayInv(itemInv);
				break;
			case 2:
				createFile(file, filename); 
				break;
			case 3:
				printFile(file, filename, itemInv);
				break;
			case 4: 
				break;
			case 5:
				break;
			}
		}
	} while (ch != 6);

	system("pause");
	return 0;
}

int menu() {
	int choice;
	cout << "**********************************\n"
		<< "*________MENOCU TOOL SHOP________*\n"
		<< "**********************************\n"
		<< "*  1. Display Inventory          *\n"
		<< "*  2. Create a Transaction File  *\n"
		<< "*  3. Update Inventory           *\n"
		<< "*  4. Display Updated Inventory  *\n"
		<< "*  5. Compute Profit Projection  *\n"
		<< "*  6. EXIT                       *\n"
		<< "**********************************\n"
		<< " Menu Choice: ";
	cin >> choice;
	return choice;
}

void displayInv(InventoryCost itemInv[SIZE]) {
	for (int i = 0; i < SIZE; i++) {
		cout << "Item #" << i+1 << ": " << endl;
		itemInv[i].print();
	}
}

void createFile(fstream &file, string filename) {
	Edit ed;
	int num;
	file.open(filename, ios::out | ios::binary);
	if (!file) {
		cout << "ERROR opening file!\n";
	}
	cout << "How many records to ammend: ";
	cin >> num;
	cout << "Her are the Transaction Codes: \n"
		<< "\tAI: Add to Inventory\n"
		<< "\tRI: Reduce from Inventory\n"
		<< "\tCW: Change Wholesale Cost\n"
		<< "\tCR: Change Retail Price\n"
		<< "\tCD: Change Description\n\n";
	for (int i = 0; i < num; i++) {
		cout << "Enter the ItemID #: ";
		cin >> ed.itID;
		cout << "Enter the Transaction Code: ";
		cin.ignore();
		getline(cin, ed.code);
		cout << "Enter New Data: ";
		getline(cin, ed.edit);
		file.write(reinterpret_cast<char *>(&ed.itID), sizeof(ed.itID));
		file.write(ed.code.c_str(), ed.code.length());
		file.write(ed.edit.c_str(), ed.edit.length());
	}
	file.close();
}
 
void printFile(fstream &file, string filename, InventoryCost inv[SIZE]) {
	Edit it;
	
	file.open(filename, ios::in | ios::binary);
	if (!file) {
		cout << "ERROR opening file!\n";
	}
	file.clear();
	file.read(reinterpret_cast<char *>(&it), sizeof(it));
	while (!file.eof()) {
		cout << it.itID << " " << it.code << " " << it.edit << endl;
		for (int i = 0; i < SIZE; i++) {
			if (inv[i].getID() == it.itID) {
				if (it.code == "AI") {
					int add = (stoi(it.edit));
					inv[i].setQty(add); 
				}
				else if (it.code == "RI") {
					int sub = (stoi(it.edit));
					inv[i].setQty(sub);
				}
				else if (it.code == "CW")
					inv[i].setWCost(stof(it.edit));
				else if (it.code == "CR")
					inv[i].setRCost(stof(it.edit));
				else if (it.code == "CD")
					inv[i].setDesc(it.edit);
				else
					cout << "Invalid Transaction Code\n";
			}
		}
		file.read(reinterpret_cast<char *>(&it), sizeof(it));
	}
	file.close();
}
Look at this snippet:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void createFile(fstream &file, string filename) {
	Edit ed;
...
		cout << "Enter the Transaction Code: ";
		cin.ignore();
		getline(cin, ed.code);
		cout << "Enter New Data: ";
		getline(cin, ed.edit);
		file.write(reinterpret_cast<char *>(&ed.itID), sizeof(ed.itID));
		file.write(ed.code.c_str(), ed.code.length());
		file.write(ed.edit.c_str(), ed.edit.length()); 
	}
	file.close();
}


How are you going to read this data back? You have two strings, that have a variable size. Remember to read this data you need to know exactly how many bytes you wrote. I would recommend something along the lines of:

Pseudo code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// To write the data:
write(ed.itID)
write(ed.code.length())
write(ed.code.c_str())
write(ed.edit.length())
write(ed.edit.c_str())

// To read the data:
size_t code_length, edit_length
read(ed.itID)
read(code_length)
ed.code.resize(code_length)
read(ed.code, code_length)
read(edit_length)
ed.edit.resize(edit_length)
read(ed.edit, edit_length)

Last edited on
That makes sense, thanks. I've never used size_t before but I'm reading up on it. As far as your pseudo code goes, can I combine the read/ write lines to something like:
1
2
3
write(ed.itID,);
write(ed.code.length(), ed.code.c_str());
.....

I see how it's working in the read, just wasn't sure if I could use both arguments in one write.
Thanks again!

edit:
Also is there any reinterpret cast needed on those reads? ie file.read(reinterpret_cast<char *>(&it.itID), sizeof(it.itID)); ?
Last edited on
can I combine the read/ write lines to something like

No. You need to write the length of the string then write the actual string data.

Also is there any reinterpret cast needed on those reads?

They won't hurt, although they're not really needed when you're writing the c_str() they are required when you're writing the sizes.

when I try to do something like file.write(ed.code.length()) I get an error. What should the other argument be then?
How did you write() the ed.itID? This is, I believe, an int so writing a the length() would use the same basic syntax.

1
2
file.write(reinterpret_cast<char *>(&ed.itID), sizeof(ed.itID));
file.write(reinterpret_cast<char *>(&ed.code.length()), sizeof(ed.code.length()));


Pages: 12