Debug Assertion Failed C++ : Vector subscript out of range - c++

I have made a program that is trying to read a .csv file and calculates the grades of the students.
I have made Student class and in the Main function I make Student type vector to read through the file and store the data in objects. Then I store all my objects in the vector .
The code was working fine, until I made some changes to take the filepath from the user. Now Its not working IDK why.. Kindly take a look into the code.
Student.h
#include <iostream>
#include <string>
using namespace std;
class student {
public:
string CMSID, firstname, lastname;
double quiz1, ass1, ass2, ass3, quiz2, quiz3, oht1, oht2, ESE, aggregate;
student();
student(string cmsid, string fn, string ln, double q1, double a1, double a2, double a3, double q2, double q3, double o1, double o2, double ese);
void calculateAggregate();
};
Students.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include "students.h"
using namespace std;
student::student() {}
student::student(string cmsid, string fn, string ln, double q1, double a1, double a2, double a3, double q2, double q3, double o1, double o2, double ese) {
CMSID = cmsid;
firstname = fn;
lastname = ln;
quiz1 = quiz1;
quiz2 = quiz2;
quiz3 = quiz3;
ass1 = a1;
ass2 = a2;
ass3 = a3;
oht1 = o1;
oht2 = o2;
ESE = ese;
}
void student::calculateAggregate()
{
aggregate = ((quiz1 + quiz2 + quiz3)*(10.0 / 30.0) + (ass1 + ass2 + ass3)*(10.0 / 30.0) + (oht1)*(20.0 / 50.0) + (oht2)*(20.0 / 50.0) + ESE * (40.0 / 100.0));
}
int main(int argc, char **argv) {
string CMSID, firstname, lastname, quiz1, ass1, ass2, ass3, quiz2, quiz3, oht1, oht2, ESE;
string Name,fileName;
ifstream gradesFile;
cout << "Place your file (.csv) in the program's directory." << endl;
cout << "Make sure that the first two rows of your file does not contain any student's data. " << endl;
cout << "Enter file name with extension(.csv): " ;
// taking filepath or filename input from the user
cin >> fileName;
gradesFile.open(fileName);
//declaring vectors of Type Student and type Double to store the objects of students containing their data (names, quizzes etc)
vector <double> aggregateList;
vector <student> students;
student *st;
//Ignoring the first two rows containing the titles of the columns
getline(gradesFile, Name);
getline(gradesFile, Name);
/// good() returns true if the file is readable and writeable
while (gradesFile.good()) {
try {
getline(gradesFile, CMSID, ',');
getline(gradesFile, firstname, ',');
getline(gradesFile, lastname, ',');
getline(gradesFile, quiz1, ',');
getline(gradesFile, ass1, ',');
getline(gradesFile, ass2, ',');
getline(gradesFile, ass3, ',');
getline(gradesFile, quiz2, ',');
getline(gradesFile, quiz3, ',');
getline(gradesFile, oht1, ',');
getline(gradesFile, oht2, ',');
getline(gradesFile, ESE, '\n');
if (quiz1.compare("") == 0) { // Replacing the empty colums with a 0 to manipulate the data correctly.
quiz1 = "0";
}
if (quiz2.compare("") == 0) {
quiz2 = "0";
}
if (quiz3.compare("") == 0) {
quiz3 = "0";
}
if (ass1.compare("") == 0) {
ass1 = "0";
}
if (ass2.compare("") == 0) {
ass2 = "0";
}
if (ass3.compare("") == 0) {
ass3 = "0";
}
if (oht1.compare("") == 0) {
oht1 = "0";
}
if (oht2.compare("") == 0) {
oht2 = "0";
}
if (ESE.compare("") == 0) {
ESE = "0";
}
// storing the data as student type objects and storing them in the vector <students>
st = new student(CMSID, firstname, lastname, stod(quiz1), stod(ass1), stod(ass2), stod(ass3), stod(quiz2), stod(quiz3), stod(oht1), stod(oht2), stod(ESE));
students.push_back(*st);
}
catch (invalid_argument) {}
}
// Calculating aggregates of all the student objects, and storing them in a separate aggregate list.
for (int j = 0; j < students.size(); j++) {
students[j].calculateAggregate();
aggregateList.push_back(students[j].aggregate);
}
// sorting the aggregateList vector to calculate the Grades correctly
sort(aggregateList.begin(), aggregateList.end());
//Calculating Deciles (10,20,30 percents and so on)
//d1 gives the data item that has 10 percent values below it, d2 has 20 percent values and so on...
double d1 = aggregateList[ceil(((aggregateList.size() + 1)*(0.1)))];
double d2 = aggregateList[ceil(((aggregateList.size() + 1)*(0.2)))];
double d3 = aggregateList[ceil(((aggregateList.size() + 1)*(0.3)))];
double d4 = aggregateList[ceil(((aggregateList.size() + 1)*(0.4)))];
double d5 = aggregateList[ceil(((aggregateList.size() + 1)*(0.5)))];
double d6 = aggregateList[ceil(((aggregateList.size() + 1)*(0.6)))];
double d7 = aggregateList[ceil(((aggregateList.size() + 1)*(0.7)))];
double d8 = aggregateList[ceil(((aggregateList.size() + 1)*(0.8)))];
double d9 = aggregateList[ceil(((aggregateList.size() + 1)*(0.9)))];
//Giving grades
ofstream A, Bplus, B, Cplus, C, Dplus, D, F;
A.open(fileName + "-A Grades.csv ");
Bplus.open(fileName + "-Bplus.csv");
B.open(fileName + "-B Grades.csv");
C.open(fileName + "-C Grades.csv");
Cplus.open(fileName + "-Cplus Grades.csv");
D.open(fileName + "-D Grades.csv");
Dplus.open(fileName + "-Dplus Grades.csv");
F.open(fileName + "-F Grades.csv");
for (int j = 0; j < students.size(); j++) {
if (A.is_open()) {
if (students[j].aggregate > d9) A << students[j].CMSID << "," << students[j].firstname << "," << students[j].lastname << "," << students[j].aggregate << endl;
}
else cout << "File coudln't be made." << endl;
if (Bplus.is_open()) {
if (students[j].aggregate > d7 && students[j].aggregate <= d9) Bplus << students[j].CMSID << "," << students[j].firstname << "," << students[j].lastname << "," << students[j].aggregate << endl;
}
else cout << "File coudln't be made." << endl;
if (B.is_open()) {
if (students[j].aggregate > d5 && students[j].aggregate <= d7) B << students[j].CMSID << "," << students[j].firstname << "," << students[j].lastname << "," << students[j].aggregate << endl;
}
else cout << "File coudln't be made." << endl;
if (Cplus.is_open()) {
if (students[j].aggregate > d4 && students[j].aggregate <= d5) Cplus << students[j].CMSID << "," << students[j].firstname << "," << students[j].lastname << "," << students[j].aggregate << endl;
}
else cout << "File coudln't be made." << endl;
if (C.is_open()) {
if (students[j].aggregate > d3 && students[j].aggregate <= d4) C << students[j].CMSID << "," << students[j].firstname << "," << students[j].lastname << "," << students[j].aggregate << endl;
}
else cout << "File coudln't be made." << endl;
if (Dplus.is_open()) {
if (students[j].aggregate > d2 && students[j].aggregate <= d3) Dplus << students[j].CMSID << "," << students[j].firstname << "," << students[j].lastname << "," << students[j].aggregate << endl;
}
else cout << "File coudln't be made." << endl;
if (D.is_open()) {
if (students[j].aggregate > d1 && students[j].aggregate <= d2) D << students[j].CMSID << "," << students[j].firstname << "," << students[j].lastname << "," << students[j].aggregate << endl;
}
else cout << "File coudln't be made." << endl;
if (F.is_open()) {
if (students[j].aggregate <= d1) F << students[j].CMSID << "," << students[j].firstname << "," << students[j].lastname << "," << students[j].aggregate << endl;
}
else cout << "File coudln't be made." << endl;
}
A.close();
B.close();
Bplus.close();
C.close();
Cplus.close();
D.close();
Dplus.close();
F.close();
system("pause");
return 0;
}
I have already searched the website for relevant errors, but couldn't understand!
Check the error here.

The error is caused by creating a vector with size n, but accessing elements beyond that.
a vector x of size n has
x[0], x[1], x[2], ..., x[n-2], x[n-1]
Accessing x[n], or x[n+1] will be outside of the range and throw the error.
ceil(((aggregateList.size() + 1)*(0.9)))
Is an expression that can be as large as n for the vector, and can overrun the memory

You need to use a debugger. Fortunately since you are using Visual Studio this is much nicer experience than using gdb.
When the assertion fails click retry in the popup, that will give you the opportunity to inspect the call stack and the values of the variables.
Alternatively if this way it is easier for you you can step through your program line by line and watch the values of the variables change...

Related

I get the error "free(): double free detected in tcache 2" while reading a file

When I try to compile my code in any IDE different than Visual Studio Code, I get the following error right after reading the file:
free(): double free detected in tcache 2.
When I delete the destructor, the program runs well, but the 'sort' function outputs all the lines as [(0,0),(0,0)]. I don't know why this happens. As mentioned, in Visual Studio Code, the program runs well from the beginning. Is there any solution to this problem? Am I missing anything?
Here are my codes and the files I am using:
main.cpp
#include <fstream>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cassert>
#include <iomanip>
#include "Line.hpp"
#include "Point.hpp"
using namespace std;
void inputLines(string filename, vector <Line>& Lines){
ifstream inFS;
inFS.open(filename);
// checking if opened
if (!inFS.is_open()){
cout << "Couldn't open the input file" << endl << endl;
return;
}
//lines:
char letter1, letter2, letter3, letter4, letter5, letter6, d1;
inFS >> letter1 >> letter2 >> letter3 >> letter4 >> letter5 >> letter6>> d1;
//{[line1:[102.0,0.9],[97.0,1.0]],
char d2, letterl, letteri, lettern, lettere, letter_1, d3, d4,d5 ,d6 ,d7 ,d8 ,d9 ,d10 ,d11 ,d12;
double linep1x, linep1y, linep2x, linep2y;
while (!inFS.eof()){
inFS >> d2 >> letterl >> letteri >> lettern >> lettere >> letter_1 >> d3 >> d4
>> linep1x >> d5 >> linep1y >> d6 >> d7 >> d8 >> linep2x >> d9 >> linep2y >> d10 >> d11 >> d12;
if(!inFS.fail() && d2 == '[' && letterl == 'l' && letteri == 'i' && lettern == 'n' && lettere == 'e' && d3 == ':' && d4 == '[' && d5 == ','
&& d6 == ']' && d7 == ',' && d8 == '[' && d9 == ',' && d10== ']' && d11 == ']' ){
Lines.push_back(Line(linep1x,linep1y,linep2x,linep2y));
}
}
inFS.close();
}
bool parallel(Line& line1, Line& line2){
double slope1 = line1.getSlope();
double slope2 = line2.getSlope();
if(slope1 == slope2){
return true;
}
return false;
}
int main (){
cout <<"\n-----------------------------------------------\n"<< " Starting unit testing ... " << "\n-----------------------------------------------\n\n";
//----------------------------------------------------------------------------------------------------------------------------------------
cout << " ---------- | Testing setters and getters functions: | ----------\n\n";
Line l1_setGet;
cout << "We want to set a line with the coordinates (1,1)(2,2) and set the slope as 1.0 and the length as 1.41 \n\n";
Point p1_setGet(1,1);
Point p2_setGet(2,2);
l1_setGet.setPoint_1(p1_setGet);
l1_setGet.setPoint_2(p2_setGet);
l1_setGet.setSlope(1);
l1_setGet.setLength(1.41);
assert(l1_setGet.getLength() == 1.41);
assert(l1_setGet.getSlope() == 1);
cout << "All test passed...\n\n";
cout << "Line: " ; l1_setGet.print() ; cout << "\nSlope: " << l1_setGet.getSlope() << "\nLength: " << l1_setGet.getLength() <<"\n\n";
//----------------------------------------------------------------------------------------------------------------------------------------
cout << " ---------- | Testing null constructors and assigning constructor: | ----------\n\n";
Point p1_constructor(-32.4,22.4);
Point p2_constructor(44.2,-31.9);
Line l1_constructor;
Line l2_constructor(p1_constructor, p2_constructor);
cout << "We want the first line to be initialized by the null constructor and the second line to be set by the other constructor \n\n";
cout << "Line 1: \n ";
l1_constructor.print(); cout << "\n\n";
cout << "Line 2: [initialized with (-32.4,22.4) and (44.2, -31.9)] \n ";
l2_constructor.print(); cout << "\n\n";
cout << "Let's also test how the constructor calculates the length and the slope. For the second line the slope would be (-0.7) and the length would be (93.9):\n\n";
cout << "Slope: " << l2_constructor.getSlope() << "\n";
cout << "Length: " << l2_constructor.getLength() << "\n\n";
//----------------------------------------------------------------------------------------------------------------------------------------
cout << " ---------- | Testing copy constructor and copy assignment operator: | ----------\n\n";
Point p1_copy(27.2,-29.3);
Point p2_copy(45.2, 11.9);
cout << "These are our test cases: \n\n";
Line l1_copy(p1_copy, p2_copy);
Line l3_copy;
cout << " Line 1: "; l1_copy.print(); cout << "\n";
cout << " Line 3: "; l3_copy.print(); cout << "\n\n";
cout << "Let's create and initialize the second line with the first line to test the copy constructor:\n\n";
Line l2_copy(l1_copy);
cout << " Line 2: "; l2_copy.print() ; cout << "\n\n";
cout << "Let's now use the assignment operator (=) to assign the second line to the third line:\n\n";
l3_copy = l2_copy;
cout << " Line 3: "; l3_copy.print() ; cout << "\n\n";
//----------------------------------------------------------------------------------------------------------------------------------------
cout << " ---------- | Testing the parallel function: | ----------\n\n";
Point p1_para(2.0, 46.4);
Point p2_para(4.0, 88.8);
Point p3_para(2.0, 52.4);
Point p4_para(4.0, 94.8);
Point p5_para(2.0, -32.4);
Point p6_para(4.0, -74.8);
cout << "These are our test cases: \n\n";
Line l1_para(p1_para,p2_para);
Line l2_para(p3_para,p4_para);
Line l3_para(p5_para,p6_para);
cout << " Line 1'slope: " << l1_para.getSlope(); cout << "\n";
cout << " Line 2'slope: " << l2_para.getSlope(); cout << "\n";
cout << " Line 3'slope: " << l3_para.getSlope(); cout << "\n\n";
cout << "Two lines are parallel when they have the same slope. Let's test the parallel function:\n\n";
cout << "Let's see if Line 1 and Line 2 are parallel: \n\n";
parallel(l1_para,l2_para) == 1 ? cout << "They are parallel\n\n" : cout << "They are not parallel\n\n";
assert(parallel(l1_para,l2_para) == 1);
cout << "Let's see if Line 1 and Line 3 are parallel: \n\n";
parallel(l1_para,l3_para) == 1 ? cout << "They are parallel\n\n" : cout << "They are not parallel\n\n";
assert(parallel(l1_para,l3_para) == 0);
cout << "All tests passed...\n\n";
//----------------------------------------------------------------------------------------------------------------------------------------
cout << " ---------- | Testing the overloaded operators (< > ==): | ----------\n\n";
Point p1_oper(2, 2);
Point p2_oper(4, 4);
Point p3_oper(2, 2);
Point p4_oper(5, 5);
Point p5_oper(2, 2);
Point p6_oper(5, 5);
Point p7_oper(2, 2);
Point p8_oper(6, 6);
cout << "These are our test cases: \n\n";
Line l1_oper(p1_oper,p2_oper);
Line l2_oper(p3_oper,p4_oper);
Line l3_oper(p5_oper,p6_oper);
Line l4_oper(p7_oper,p8_oper);
cout << " Line 1: " ; l1_oper.print(); cout << " Length; " << l1_oper.getLength() <<"\n";
cout << " Line 2: " ; l2_oper.print(); cout << " Length; " << l2_oper.getLength() <<"\n";
cout << " Line 3: " ; l3_oper.print(); cout << " Length; " << l3_oper.getLength() <<"\n";
cout << " Line 4: " ; l4_oper.print(); cout << " Length; " << l4_oper.getLength() <<"\n\n";
cout << " Let's test (<): \n\n";
cout << "(Line 1 < Line 2): ";
l1_oper < l2_oper == true ? cout << "True\n\n" : cout << "False\n\n";
assert( l1_oper < l2_oper == true );
cout << "(Line 2 < Line 1): ";
l2_oper < l1_oper == true ? cout << "True\n\n" : cout << "False\n\n";
assert( l2_oper < l1_oper == false );
//----------------------------------------------------------------------------------------------------------------------------------------
cout << " Let's test (>): \n\n";
cout << "(Line 2 > Line 3): ";
l2_oper > l3_oper == true ? cout << "True\n\n" : cout << "False\n\n";
assert( l2_oper > l3_oper == false );
cout << "(Line 4 > Line 1): ";
l4_oper > l1_oper == true ? cout << "True\n\n" : cout << "False\n\n";
assert( l4_oper > l1_oper == true );
//----------------------------------------------------------------------------------------------------------------------------------------
cout << " Let's test (==): \n\n";
cout << "(Line 2 == Line 3): ";
l2_oper == l3_oper == true ? cout << "True\n\n" : cout << "False\n\n";
assert( l2_oper == l3_oper == true );
cout << "(Line 1 == Line 4): ";
l1_oper == l4_oper == true ? cout << "True\n\n" : cout << "False\n\n";
assert( l1_oper == l4_oper == false );
//----------------------------------------------------------------------------------------------------------------------------------------
cout << "All tests passed...\n\n";
cout << " ---------- | Testing the file reader function: | ----------\n\n"; //--------------------------------------------------------------------
vector <Line> Lines;
string filename = "lines.txt";
cout << "Reading file...\n\n";
inputLines(filename, Lines);
cout << "Outputting extracted coordinates out of the file: \n\n";
for (int i = 0 ; i < Lines.size() ; i++){
Lines.at(i).print();
cout << endl;
}
cout << endl;
cout << " ---------- | Testing the sort function: | ----------\n\n"; //--------------------------------------------------------------------
Lines.clear();
string filename_2 = "lines_2.txt";
cout << "Reading file with non-sorted values...\n\n";
inputLines(filename_2, Lines);
cout << "Outputting extracted coordinates out of the file: \n\n";
for (int i = 0 ; i < Lines.size() ; i++){
Lines.at(i).print();
cout << endl;
}
cout << endl;
cout << "Sorting... \n\n";
sort(Lines.begin(), Lines.end());
cout << "Outputting sorted values: \n\n";
for (int i = 0 ; i < Lines.size() ; i++){
Lines.at(i).print();
cout << endl;
}
cout << endl;
//----------------------------------------------------------------------------------------------------------------------------------------
Line l1_cout(1,2,3,4);
cout << "Overloading \"cout\" to print an object (in this case, a line with the coordinates (1,2),(3,4): \n\n";
cout << l1_cout << endl;
cout << endl;
//----------------------------------------------------------------------------------------------------------------------------------------
cout << " ---------- | Testing the insertion operator (>> cin): | ----------\n\n";
Line l1_cin;
cout << "Enter a line in the format [(x1,y1),(x2,y2)] " << endl << endl;
cin >> l1_cin;
cout << "\nYou entered: " << endl << endl;
cout << "------- ";
l1_cin.print();
cout << " -------\n\n";
return 0;
}
Line.hpp
#include <cmath>
#include "Point.hpp"
#include <iomanip>
using namespace std;
#ifndef LINE_H
#define LINE_H
class Line{
private:
Point* p1;
Point* p2;
double slope;
double length;
public:
Line(); //null constructor
Line(Point p1, Point p2);
Line(double linep1x, double linep1y, double linep2x, double linep2y);
// !accessors and mutators
//---------------------------------------//
void setPoint_1 (double x, double y){
p1->setX(x);
p1->setY(y);
calculateLength();
calculateSlope();
}
void setPoint_1 (Point p){
*p1=p;
calculateLength();
calculateSlope();
}
Point getPoint_1() const{
return *p1;
}
//---------------------------------------//
void setPoint_2 (double x, double y){
p2->setX(x);
p2->setY(y);
calculateLength();
calculateSlope();
}
void setPoint_2 (Point p){
*p2=p;
calculateLength();
calculateSlope();
}
Point getPoint_2() const{
return *p2;
}
//---------------------------------------//
void setSlope(double s){
this->slope = s;
}
void calculateSlope(){
slope = ( (p2->getY()) - (p1->getY()) ) / ((p2->getX()) - (p1->getX()) );
}
double getSlope() const{
return this->slope;
}
//---------------------------------------//
void setLength(double l){
this->length = l;
}
void calculateLength(){
length = sqrt( (pow( ( (p2->getX()) - (p1->getX()) ) , 2) ) + (pow(( (p2->getY()) - (p1->getY())), 2 ) ) );
}
double getLength() const{
return this->length;
}
//---------------------------------------//
//!print
void print() const;
//!destructor
~Line();
//!copy constructor
Line(const Line& l);
//!assignment
Line& operator=(const Line& line);
//! overloading operators
bool operator==(const Line& line);
bool operator<(const Line& line);
bool operator>(const Line& line);
friend ostream& operator<<(ostream& out, Line& L);
friend istream& operator>>(istream& in, Line& L);
};
#endif
Line::Line(){ //*null constructor
slope = 0;
length= 0;
p1 = new Point();
p2 = new Point();
}
Line::Line(double linep1x, double linep1y, double linep2x, double linep2y){
p1 = new Point ;
p2 = new Point ;
p1->setX(linep1x);
p1->setY(linep1y);
p2->setX(linep2x);
p2->setY(linep2y);
//The distance between two points is given by d(P, Q) = √(x2 − x1)² + (y2 − y1)²
calculateLength();
//The slope of a line, given two points, is defined as m = (y2-y1)/(x2-x1)
calculateSlope();
}
Line::Line(Point point1, Point point2){ //*overload constructor to calculate length and slope
double x1 = point1.getX();
double y1 = point1.getY();
double x2 = point2.getX();
double y2 = point2.getY();
p1 = new Point(x1,y1);
p2 = new Point(x2,y2);
//The distance between two points is given by d(P, Q) = √(x2 − x1)² + (y2 − y1)²
calculateLength();
//The slope of a line, given two points, is defined as m = (y2-y1)/(x2-x1)
calculateSlope();
}
//*destructor
Line::~Line(){
delete p1;
delete p2;
}
//*copy constructor
Line::Line(const Line& line){
this->p1 = new Point ;
this->p2 = new Point ;
this->p1 = line.p1;
this->p2 = line.p2;
length = line.length;
slope = line.slope;
}
//*assignment operator
Line& Line::operator=(const Line& line){
if(this!=&line){
delete this->p1;
delete this->p2;
this->p1 = new Point ;
this->p2 = new Point ;
this->p1 = line.p1;
this->p2 = line.p2;
}
return *this;
}
// * =
bool Line::operator==(const Line& line){
if(this->length == line.length){
return true;
}
return false;
}
//* < operator
bool Line::operator<(const Line& line){
if(this->length < line.length){
return true;
}
return false;
}
//* > operator
bool Line::operator>(const Line& line){
return (!(this->length < line.length) && !(this->length == line.length));
}
// * << operator (cout)
ostream& operator<<(ostream& out, Line& L){
out << "[(" << (L.p1->getX()) << ", " << (L.p1->getY()) <<"), (" << L.p2->getX() << ", " << (L.p2->getY()) <<")]";
return out;
}
// * >> operator (cin)
istream& operator>>(istream& in, Line& L){
char d1, d2, d3, d4, d5, d6, d7, d8, d9;
double x1, y1, x2, y2;
//[(x1,y1),(x2,y2)]
in >> d1 >> d2 >> x1 >> d3 >> y1 >> d4 >> d5 >> d6 >> x2 >> d7 >> y2 >> d8 >> d9;
if(!(d1 == '[' && d2 == '(' && d3 == ',' && d4 == ')' && d5 == ',' && d6 == '(' && d7 == ',' && d8 == ')' && d9 == ']' )){
cout << "Invalid format" << endl;
}
else{
L.setPoint_1(x1,y1);
L.setPoint_2(x2, y2);
}
return in;
}
//* print function
void Line::print() const{
cout << fixed << setprecision (1) << "[" << "(" << p1->getX() <<", " << p1->getY() << ")" << "," << "(" << p2->getX() << ", " << p2->getY() << ")" << "]" ;
}
Point.hpp
#include <cmath>
#include <string>
using namespace std;
#ifndef POINT_H
#define POINT_H
class Point{
private: // can only be used by public
double x;
double y;
public:
///constructor
Point (double X=0, double Y=0) : x(X), y(Y) {}
//functions
void setX(double x) {this->x= x ;}
double getX() const {return this->x ;}
void setY(double y) {this->y=y ;}
double getY() const {return this->y ;}
void print() const;
friend bool operator== (Point lhp, Point rhp);
friend bool operator> (Point lhp, Point rhp);
friend bool operator< (Point lhp, Point rhp);
};
void Point::print() const{
cout << "(" << this->x<< ","<<this->y<<")" << endl;
}
bool operator== (Point lhp, Point rhp){
if((lhp.x == rhp.x && lhp.y == rhp.y)){
return true;
}
else{
return false;
}
}
bool operator> (Point lhp, Point rhp){
int euclideanLeft, euclideanRight;
euclideanLeft = sqrt((pow(lhp.x, 2))+(pow(lhp.y,2)));
euclideanRight = sqrt((pow(rhp.x, 2))+(pow(rhp.y,2)));
if((euclideanLeft > euclideanRight)){
return true;
}
else{
return false;
}
}
bool operator< (Point lhp, Point rhp){
return !((lhp.x > rhp.x, lhp.y > rhp.y) || (lhp.x == rhp.x, lhp.y == rhp.y));
}
#endif
lines.txt
lines:
{
[line1:[102.0,0.9],[97.0,1.0]],
[line2:[103.0,0.8],[98.0,1.0]],
[line3:[104.0,0.7],[99.0,1.0]],
[line4:[105.0,0.6],[100.0,1.0]]
}
lines_2.txt
lines:
{
[line2:[103.0,0.8],[98.0,1.0]],
[line1:[102.0,0.9],[97.0,1.0]],
[line4:[105.0,0.6],[100.0,1.0]],
[line3:[104.0,0.7],[99.0,1.0]]
}
Ignoring the fact that there is no real reason why Line is keeping pointers to Points....
Your copy constructor is only doing a shallow copy which means you end up with multiple Line instances pointing to the same points:
Line::Line(const Line& line){
this->p1 = new Point ;
this->p2 = new Point ;
this->p1 = line.p1; // this overwrites the newly allocated
this->p2 = line.p2; // p1 and p2 above.
length = line.length;
slope = line.slope;
}
Should be something like:
Line::Line(const Line& line){
this->p1 = new Point(line.p1->getX(), line.p1->getY());
this->p2 = new Point(line.p2->getX(), line.p2->getY());
length = line.length;
slope = line.slope;
}
If this is not for some class that requires the Points in Line to be pointers I would really recommend you consider just storing the Points in the lines. It will solve a lot of headaches.

Why am I getting error messages in my "customer.cpp" file

I am unsure about why I am getting this error message when I hover over purchaseArray in my string Customer::save() method in the customer.cpp file:
identifier is undefined
And this error message when I hover over getline in the void Customer::parse(string line) method in the customer.cpp file:
no instance of overloaded function "getline" matches the argument list argument types are: (std::stringstream, int, char)
Code in the Customer.cpp file:
#include "Customer.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include<utility>
using namespace std;
//default constructor
Customer::Customer() {
}
//Full constructor
Customer::Customer(int customerID, string title, string name, int numOfPurchases, int purchase1, int purchase2, int purchase3, string type)
{
this->customerID = customerID;
this->title = title;
this->name = name;
this->numOfPurchases = numOfPurchases;
purchases = new int[3];
purchases[0] = purchase1;
purchases[1] = purchase2;
purchases[2] = purchase3;
this->type = type;
}
Customer::Customer(const Customer& source) //copy constructor
{
cout << "copy constructor called" << endl;
this->customerID = source.customerID;
this->title = source.title;
this->name = source.name;
this->numOfPurchases = source.numOfPurchases;
this->purchases = new int[3];
purchases[0] = source.purchases[0];
purchases[1] = source.purchases[1];
purchases[2] = source.purchases[2];
this->type = source.type;
}
//overloaded assignment operator=
Customer& Customer::operator= (Customer& otherCustomer)
{
cout << "Overloaded assignment operator= called" << endl;
//self-assignment guard
if (this == &otherCustomer)
return *this; //refernce to the same object
// copy data from the source (rhs) to this object (the destination)
name = otherCustomer.name;
//must make a new scores object to store a copy of the other student
if (purchases != nullptr)
delete[] purchases;
purchases = new int[3];
for (int i = 0; i < 3; i++) {
purchases[i] = otherCustomer.purchases[i];
}
//return this existing object so we can chain this operator
return *this;
}
string Customer::save()
{
stringstream out;
out << this->customerID << ";";
out << this->title << ";";
out << this->name << ";";
out << this->numOfPurchases << ";";
int* purchases = 0;
purchases = purchases | (purchaseArray[0] << 24);
purchases = purchases | (purchaseArray[1] << 16);
purchases = purchases | (purchaseArray[2] << 8);
out << this->type << ";";
out.flush();
return out.str();
}
void Customer::parse(string line)
{
stringstream in(line);
string customerIDLine;
getline(in, customerIDLine, ';');
customerID = stoi(customerIDLine);
getline(in, title, ';');
getline(in, name, ';');
int numOfPurchases;
getline(in, numOfPurchases, ';');
int s = stoi(numOfPurchases);
purchasesArray[0] = (s & (255 << 16)) >> 16;
purchasesArray[1] = (s & (255 << 8)) >> 8;
purchasesArray[2] = s & 255;
getline(in, type, ';');
}
Customer::~Customer() {
cout << "Destructor ~Customer called" << endl;
delete[] purchases;
}
// Overloaded insertion operator (Outputs Character object data as an output stream)
// Defined in header file as a "friend" function, as it is not a member function
//
ostream& operator<<(ostream& out, Customer& customer)
{
cout << "Customer details ( output by insertion operator<< )" << endl;
cout << "Customer ID: " << customer.customerID << endl;
cout << "Title: " << customer.title << endl;
cout << "Name: " << customer.name << endl;
cout << "Number of purchases: " << customer.numOfPurchases << endl;
cout << "Purchases: ";
for (int i = 0; i < 3; i++)
{
if (i > 0) cout << ",";
cout << customer.purchases[i];
}
cout << "Type: " << customer.type << endl;
return out;
}
istream& operator>> (istream& in, Customer& customer)
{
cout << "Enter Customer details ( using the extraction operator>> )" << endl;
cout << "Enter Customer ID: " << endl;
cin >> customer.customerID;
cout << "Enter Title: " << endl;
getline(cin, customer.title);
cout << "Enter Name: " << endl;
getline(cin, customer.name);
cout << "Enter Number of Purchases: ";
cin >> customer.numOfPurchases;
cout << "Enter Purchases: ";
cin >> customer.purchases[0];
cin >> customer.purchases[1];
cin >> customer.purchases[2];
cout << "Enter Type";
getline(cin, customer.type);
cout << endl;
return in;
}
int Customer::getCustomerID()
{
return customerID;
}
string Customer::getTitle()
{
return title;
}
string Customer::getName()
{
return name;
}
int Customer::getNumOfPurchases()
{
return numOfPurchases;
}
int* Customer::getPurchases()
{
return purchases;
}
string Customer::getType()
{
return type;
}
void Customer::setCustomerID(int customerID)
{
if (customerID < 1) {
cout << "Customer ID has to be equal to 1 or more" << endl; //Changed all the "throw invalid_argument" messages to cout as they were causing an issue with my main.cpp file and an abort message kept appearing every time I ran my main.cpp file.
}
this->customerID = customerID;
}
void Customer::setTitle(string title)
{
if (title.length() < 2) {
cout << "Title has to be more than or equal to 2 characters" << endl;
}
this->title = title;
}
void Customer::setName(string name)
{
if (name.length() < 4) {
cout << "Length of name should be more than or equal to 4 characters" << endl;
}
this->name = name;
}
//Got help ith this on stack overflow as I was using "&&" instead of using "||" for the if statement
void Customer::setNumOfPurchases(int numOfPurchases)
{
if(numOfPurchases <0 || numOfPurchases > 10000){
cout << "Number of purchases should be between 0 to 10000" << endl;
}
this->numOfPurchases = numOfPurchases;
}
void Customer::setPurchases(int purchase1, int purchase2, int purchase3)
{
if (purchase1 < 0 || purchase2 < 0 || purchase3 < 0) {
cout << "Purchases must be more than or equal to zero" << endl;
}
}
//Got help from stack overflow on comparing strings as I originally didnt use "type.compare"
void Customer::setType(string type) {
if (type.compare("New") !=0 || type.compare("Either") !=0) {
cout << "Type of purchase has to be New or Either" << endl;
}
}
Code in the Customer.h file:
#pragma once
#include<iostream>
using namespace std;
#include<string>
class Customer
{
private:
int customerID;
string title;
string name;
int numOfPurchases;
int* purchases;
string type;
public:
Customer(); // default constructor
Customer(int customerID, string title, string name, int numOfPurchases, int purchase1, int purchase2, int purchase3, string type);
//copy overload assignment
Customer& operator=(Customer& otherCustomer);
Customer(const Customer& source);
string save();
void parse(string line);
~Customer(); //destructor
//Getters and Setters
void setCustomerID(int customerID);
void setTitle(string title);
void setName(string name);
void setNumOfPurchases(int numOfPurchases);
void setPurchases(int purchase1, int purchase2, int purchase3);
void setType(string type);
int getCustomerID();
string getTitle();
string getName();
int getNumOfPurchases();
int* getPurchases();
string getType();
void printCustomer() {
cout << customerID << "," << title << "," << name << "," << numOfPurchases << "," << purchases << "," << type << endl;
}
friend std::ostream& operator<<(std::ostream& out, Customer& customer); // overloaded operator<<
friend istream& operator>> (istream& in, Customer& customer); // overloaded operator >>
};
Code from the Main.cpp file:
// Repeat_Assessment_C++_AislingSmith.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include "Customer.h"
using namespace std;
void OutputFileStream();
void parseLine(const string& str);
void InputFileStream();
void save(vector<Customer> customers);
void load(vector<Customer>& customers);
void addCustomer(vector<Customer>& vect);
//void printActions();
void OutputFileStream()
{
cout << "Creating and writing to file: Customer.txt" << endl;
ofstream outStream("customers.txt"); // write mode (overwrites existing data)
if (outStream.good())
{
int customerID = 150033;
outStream << "This is a line of text.\n";
outStream << "This is another line of text.\n";
outStream << "This is a line of text.\n";
int numOfPurchases = 4;
int purchases = 0;
outStream << customerID << "Mr" << "Jack" << "New" << numOfPurchases << purchases << endl;
outStream.close(); // close file
cout << "File written.\n" << endl;
}
else
cout << "Unable to open file";
}
void parseLine(const string& str) {
stringstream strStream(str); //create string stream from the string
// int customerID;
string title;
string name;
string type;
//int numOfPurchases;
//int purchases;
string s;
int customerID = 150033;
getline(strStream, s, ';');
customerID = stoi(s);
getline(strStream, title, ';');
getline(strStream, name, ';');
getline(strStream, type, ';');
int numOfPurchases = 4;
getline(strStream, s, ';');
numOfPurchases = stoi(s);
int purchases = 0;
getline(strStream, s, ';');
purchases = stoi(s);
int* purchasesArray = new int[3];
purchasesArray[0] = (purchases & (255 << 16)) >> 16;
purchasesArray[1] = (purchases & (255 << 8)) >> 8;
purchasesArray[2] = purchases & 255;
for (int i = 0; i < 3; i++)
{
int purchasesArray[3];
}
cout << " CustomerID: " << customerID << "Title:" << title << " Name: " << name << " Type:" << type << " Number of Purchases: " << numOfPurchases << "Purchases: " << purchases << endl;
}
void InputFileStream() {
cout << "Reading from a semi-colon delimited txt file" << endl;
string line;
ifstream inStream("customers.txt"); //opens file as an input file stream
if (inStream.good()) //if the file is opened successfully and not empty
{
while (getline(inStream, line)) //reads line until false return
{
parseLine(line);
}
inStream.close();
}
else
cout << "unable to open file or the file is empty!";
}
void save(vector<Customer> customers)
{
ofstream out("customers.txt");
if(out)
{
for (Customer& c : customers)
{
out << c.save();
}
out.flush();
out.close();
}
else
{
cout << "Error Writing to File" << endl;
}
}
void load(vector<Customer>& customers)
{
ifstream in("customers.txt");
if (in) {
string line;
while (!in.eof())
{
getline(in, line);
if (line != "")
{
Customer c;
c.parse(line);
customers.push_back(c);
}
}
}
}
void addCustomer(vector<Customer>& customers) {
Customer customer;
cin >> customer;
customers.push_back(customer);
}
int main()
{
InputFileStream();
vector<Customer> customers;
Customer c;
Customer cust1;
cust1.setCustomerID(150032);
cust1.setTitle("Mr");
cust1.setName("Joey");
cust1.setNumOfPurchases(3);
cust1.setPurchases(366, 352, 334);
cust1.setType("New");
cout << cust1.getCustomerID() << endl;
cout << cust1.getTitle() << endl;
cout << cust1.getName() << endl;
cout << cust1.getNumOfPurchases() << endl;
cout << cust1.getPurchases() << endl;
cout << cust1.getType() << endl;
return 0;
}
First Problem
The first error is pretty clear, purchaseArray is nowhere defined (at least not in the code you show here) and you probably meant just purchases or this->purchases? Allthough I got no clue what you tried to achieve with the int *purchases there.
Second Problem
The second one occurs, because the way you try to read an integer from a stream is flawed.
It's about this piece of code from Customer::parse
int numOfPurchases; // declare int
getline(in, numOfPurchases, ';'); // error, second parameter must be std::string!
int s = stoi(numOfPurchases); // numOfPurchases is already an int
You probably wanted this:
std::string numOfPurchasesBuf; // temporary buffer
getline(in, numOfPurchasesBuf, ';'); // read data to string
int s = stoi(numOfPurchasesBuf); // convert to int
and since all of those lines read some member variable you probably want to set this one as well:
this->numOfPurchases = s;

When reading in a .txt file in c++, how do I change a number that's stored in the .txt file as "365048" to "36, 50, 48" using a dynamic array?

I have been trying to separate a number stored in a .txt file as "365048" to "36, 50, 48" when it has been read into my program using a dynamic array and i'm not sure where I am going wrong. The variable i'm having the issue with is int* purchases.
Code from Main.cpp
// Repeat_Assessment_C++_Aisling.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include "Customer.h"
using namespace std;
void OutputFileStream();
void parseLine(const string& str);
void InputFileStream();
//void printActions();
void OutputFileStream()
{
cout << "Creating and writing to file: Customer.txt" << endl;
ofstream outStream("customers.txt"); // write mode (overwrites existing data)
if (outStream.good())
{
int customerID = 150033;
outStream << "This is a line of text.\n";
outStream << "This is another line of text.\n";
outStream << "This is a line of text.\n";
int numOfPurchases = 4;
int purchases = 0;
outStream << customerID << "Mr" << "Jack" << "New" << numOfPurchases << purchases << endl;
outStream.close(); // close file
cout << "File written.\n" << endl;
}
else
cout << "Unable to open file";
}
void parseLine(const string& str) {
stringstream strStream(str); //create string stream from the string
// int customerID;
string title;
string name;
string type;
//int numOfPurchases;
//int purchases;
string s;
int customerID = 150033;
getline(strStream, s, ';');
customerID = stoi(s);
getline(strStream, title, ';');
getline(strStream, name, ';');
getline(strStream, type, ';');
int numOfPurchases = 4;
getline(strStream, s, ';');
numOfPurchases = stoi(s);
int purchases = 0;
getline(strStream, s, ';');
purchases = stoi(s);
int* purchasesArray = new int[3];
purchasesArray[0] = (purchases & (255 << 24)) >> 24;
purchasesArray[1] = (purchases & (255 << 16)) >> 16;
purchasesArray[2] = (purchases & (255 << 8)) >> 8;
for (int i = 0; i < 3; i++)
{
int purchasesArray[3];
}
cout << " CustomerID: " << customerID << "Title:" << title << " Name: " << name << " Type:" << type << " Number of Purchases: " << numOfPurchases << "Purchases: " << purchases << endl;
}
void InputFileStream() {
cout << "Reading from a semi-colon delimited txt file" << endl;
string line;
ifstream inStream("customers.txt"); //opens file as an input file stream
if (inStream.good()) //if the file is opened successfully and not empty
{
while (getline(inStream, line)) //reads line until false return
{
parseLine(line);
}
inStream.close();
}
else
cout << "unable to open file or the file is empty!";
}
int main()
{
InputFileStream();
Customer cust1;
cust1.setCustomerID(150032);
cust1.setTitle("Mr");
cust1.setName("Joey");
cust1.setNumOfPurchases(3);
cust1.setPurchases(366, 352, 334);
cust1.setType("New");
cout << cust1.getCustomerID() << endl;
cout << cust1.getTitle() << endl;
cout << cust1.getName() << endl;
cout << cust1.getNumOfPurchases() << endl;
cout << cust1.getPurchases() << endl;
cout << cust1.getType() << endl;
return 0;
}
Code from Customer.h
#pragma once
#include<iostream>
using namespace std;
#include<string>
class Customer
{
private:
int customerID;
string title;
string name;
int numOfPurchases;
int* purchases;
string type;
public:
Customer(); // default constructor
Customer(int customerID, string title, string name, int numOfPurchases, int purchase1, int purchase2, int purchase3, string type);
//copy overload assignment
Customer& operator=(Customer& otherCustomer);
Customer(const Customer& source);
~Customer(); //destructor
//Getters and Setters
void setCustomerID(int customerID);
void setTitle(string title);
void setName(string name);
void setNumOfPurchases(int numOfPurchases);
void setPurchases(int purchase1, int purchase2, int purchase3);
void setType(string type);
int getCustomerID();
string getTitle();
string getName();
int getNumOfPurchases();
int* getPurchases();
string getType();
void printCustomer() {
cout << customerID << "," << title << "," << name << "," << numOfPurchases << "," << purchases << "," << type << endl;
}
friend std::ostream& operator<<(std::ostream& out, Customer& customer); // overloaded operator<<
friend istream& operator>> (istream& in, Customer& customer); // overloaded operator >>
};
Code from Customer.cpp
#include "Customer.h"
#include <iostream>
#include <string>
#include<utility>
using namespace std;
//default constructor
Customer::Customer() {
}
//Full constructor
Customer::Customer(int customerID, string title, string name, int numOfPurchases, int purchase1, int purchase2, int purchase3, string type)
{
this->customerID = customerID;
this->title = title;
this->name = name;
this->numOfPurchases = numOfPurchases;
purchases = new int[3];
purchases[0] = purchase1;
purchases[1] = purchase2;
purchases[2] = purchase3;
this->type = type;
}
Customer::Customer(const Customer& source) //copy constructor
{
cout << "copy constructor called" << endl;
this->customerID = source.customerID;
this->title = source.title;
this->name = source.name;
this->numOfPurchases = source.numOfPurchases;
this->purchases = new int[3];
purchases[0] = source.purchases[0];
purchases[1] = source.purchases[1];
purchases[2] = source.purchases[2];
this->type = source.type;
}
//overloaded assignment operator=
Customer& Customer::operator= (Customer& otherCustomer)
{
cout << "Overloaded assignment operator= called" << endl;
//self-assignment guard
if (this == &otherCustomer)
return *this; //refernce to the same object
// copy data from the source (rhs) to this object (the destination)
name = otherCustomer.name;
//must make a new scores object to store a copy of the other student
if (purchases != nullptr)
delete[] purchases;
purchases = new int[3];
for (int i = 0; i < 3; i++) {
purchases[i] = otherCustomer.purchases[i];
}
//return this existing object so we can chain this operator
return *this;
}
Customer::~Customer() {
cout << "Destructor ~Customer called" << endl;
delete[] purchases;
}
// Overloaded insertion operator (Outputs Character object data as an output stream)
// Defined in header file as a "friend" function, as it is not a member function
//
ostream& operator<<(ostream& out, Customer& customer)
{
cout << "Customer details ( output by insertion operator<< )" << endl;
cout << "Customer ID: " << customer.customerID << endl;
cout << "Title: " << customer.title << endl;
cout << "Name: " << customer.name << endl;
cout << "Number of purchases: " << customer.numOfPurchases << endl;
cout << "Purchases: ";
for (int i = 0; i < 3; i++)
{
if (i > 0) cout << ",";
cout << customer.purchases[i];
}
cout << "Type: " << customer.type << endl;
return out;
}
istream& operator>> (istream& in, Customer& customer)
{
cout << "Enter Customer details ( using the extraction operator>> )" << endl;
cout << "Enter Customer ID: " << endl;
cin >> customer.customerID;
cout << "Enter Title: " << endl;
getline(cin, customer.title);
cout << "Enter Name: " << endl;
getline(cin, customer.name);
cout << "Enter Number of Purchases: ";
cin >> customer.numOfPurchases;
cout << "Enter Purchases: ";
cin >> customer.purchases[0];
cin >> customer.purchases[1];
cin >> customer.purchases[2];
cout << "Enter Type";
getline(cin, customer.type);
cout << endl;
return in;
}
int Customer::getCustomerID()
{
return customerID;
}
string Customer::getTitle()
{
return title;
}
string Customer::getName()
{
return name;
}
int Customer::getNumOfPurchases()
{
return numOfPurchases;
}
int* Customer::getPurchases()
{
return purchases;
}
string Customer::getType()
{
return type;
}
void Customer::setCustomerID(int customerID)
{
if (customerID < 1) {
cout << "Customer ID has to be equal to 1 or more" << endl; //Changed all the "throw invalid_argument" messages to cout as they were causing an issue with my main.cpp file and an abort message kept appearing every time I ran my main.cpp file.
}
this->customerID = customerID;
}
void Customer::setTitle(string title)
{
if (title.length() < 2) {
cout << "Title has to be more than or equal to 2 characters" << endl;
}
this->title = title;
}
void Customer::setName(string name)
{
if (name.length() < 4) {
cout << "Length of name should be more than or equal to 4 characters" << endl;
}
this->name = name;
}
//Got help ith this on stack overflow as I was using "&&" instead of using "||" for the if statement
void Customer::setNumOfPurchases(int numOfPurchases)
{
if(numOfPurchases <0 || numOfPurchases > 10000){
cout << "Number of purchases should be between 0 to 10000" << endl;
}
this->numOfPurchases = numOfPurchases;
}
void Customer::setPurchases(int purchase1, int purchase2, int purchase3)
{
if (purchase1 < 0 || purchase2 < 0 || purchase3 < 0) {
cout << "Purchases must be more than or equal to zero" << endl;
}
}
//Got help from stack overflow on comparing strings as I originally didnt use "type.compare"
void Customer::setType(string type) {
if (type.compare("New") !=0 || type.compare("Either") !=0) {
cout << "Type of purchase has to be New or Either" << endl;
}
}
Text in my customers.txt file:
150034;Mr;Sean Brennan;New;5;365048;\n
150035;Mrs;Aisling Smith;Regular;6;375149;\n
150036;Mr;John Smith;New;7;385250;\n
150037;Mrs;Sharon Hanratty;Regular;8;395351;
Trouble seems to be that you are trying to divide input into its hexadecimal digits and it looks like you are looking for decimal digits.
May be you can do something like following:
purchasesArray[0] = purchases / 10000;
purchasesArray[1] = (purchases / 100) % 100;
purchasesArray[2] = purchases % 100;
instead of
purchasesArray[0] = (purchases & (255 << 24)) >> 24;
purchasesArray[1] = (purchases & (255 << 16)) >> 16;
purchasesArray[2] = (purchases & (255 << 8)) >> 8;
Note: If your input is pretty big, above solution can be bad performancewise.
Note 2: Even if you really want hexadecimal digits, your parsing is problematic.
Edit for note 2:
To parse a 6 digit hexadecimal number you might do this:
purchasesArray[0] = (purchases & (255 << 16)) >> 16;
purchasesArray[1] = (purchases & (255 << 8)) >> 8;
purchasesArray[2] = purchases & 255;
your code seems to parse first 6 digits of an 8 digit hex number.
That is why I called it problematic.

Program eating a first letter of a line

So I'm practicing working with files in C++ a bit. I've created a simple program that loads Student's name, index number, date of birth and grades from STUDENT.txt, counts the student's average, and writes it all down in a form below to a different file.
It all works like a charm, except one thing: It eats up the first letter of every line. EXAMPLE:
I have a STUDENT.txt file that looks like this:
Alice Cooper
225883
21/6/1986
6,6,8,9,10
Zakk Wylde
27568
14/5/1978
6,6,6,6,6
So the first student, Cooper, will be processed correctly, but everyone else in the file won't. They'll be written down as 'akk Wylde'...
So everything but a name is OK.
I was hoping someone could tell me what exactly is going on, I'm guessing it's eating up a '\n' and another character, but I couldn't find it with debugging.
// Student_datoteka.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
std::string toString(int day, int month, int year) {
std::string d, m, g, ret;
d = std::to_string(day);
m = std::to_string(month);
g = std::to_string(year);
ret += d;
ret += "/";
ret += m;
ret += "/";
ret += g;
return ret;
}
int main()
{
std::fstream load("STUDENTI.txt", std::ios::in);
std::ofstream write("IZVJESTAJ.txt");
write << std::setw(30) << std::left << "Student"
<< std::setw(10) << "Indeks"
<< std::setw(20) << "Datum rodjenja"
<< std::setw(10) << "Prosjek" << std::endl;
write << std::setw(30) << std::left << "-------"
<< std::setw(10) << "------"
<< std::setw(20) << "--------------"
<< std::setw(10) << "-------" << std::endl;
if (!write)
std::cout << "ERROR!";
std::string name;
int indeks(0), day(0), month(0), year(0);
char sign(0), sign2(0);
int grades[30];
double average(0);
while (std::getline(load, name)) {
if (load.eof()) break;
load >> indeks;
load >> day >> sign >> mjesec >> sign2 >> year;
int i(0);
while (load >> grades[i]) {
load >> sign;
average += grades[i];
i++;
}
average /= double(i);
std::string datum = toString(day, month, year);
write << std::setw(30) << std::left << name
<< std::setw(10) << indeks
<< std::setw(20) << datum
<< std::setw(10) << std::setprecision(2)
<< average<< std::endl;
average = 0;
if (load.eof()) break;
load.clear();
}
return 0;
}
This is the output: http://prntscr.com/jvm3jn
I have made a small improvements on your code so please, if you don't like, take only the working part. Note that my code can be improved and generalized even more but I am leaving that to you.
Hope you would like my solution:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <iomanip>
typedef struct Student
{
std::string name;
int index_no;
int day_of_birth;
int month_of_birth;
int year_of_birth;
std::vector<int> grades;
double avg_grade;
} Student;
std::string date_to_string(int day, int month, int year)
{
std::string d, m, g, ret;
d = std::to_string(day);
m = std::to_string(month);
g = std::to_string(year);
ret += d;
ret += "/";
ret += m;
ret += "/";
ret += g;
return ret;
}
void get_date_from_str(int& day, int& month, int& year, std::string const& str)
{
std::stringstream ss(str);
ss >> day;
ss.ignore(1);
ss >> month;
ss.ignore(1);
ss >> year;
}
void get_numbers_from_str(std::vector<int>& vec, std::string const& str)
{
std::stringstream ss(str);
int i;
while (ss >> i)
{
vec.push_back(i);
ss.ignore(1);
}
}
double calculate_avg(std::vector<int> const& vec)
{
int sum = 0;
for (auto item : vec)
{
sum += item;
}
return (double) sum / vec.size();
}
int main()
{
std::ifstream students_file("students.txt");
std::ofstream report_file("report.txt");
if (students_file.is_open() && report_file.is_open())
{
report_file << std::setw(30) << std::left << "Student"
<< std::setw(10) << "Indeks"
<< std::setw(20) << "Datum rodjenja"
<< std::setw(10) << "Prosjek" << std::endl;
report_file << std::setw(30) << std::left << "-------"
<< std::setw(10) << "------"
<< std::setw(20) << "--------------"
<< std::setw(10) << "-------" << std::endl;
std::vector<Student> students;
std::string name;
while (std::getline(students_file, name))
{
std::string index_no;
std::string date_of_birth;
std::string grades;
Student student;
student.name = name;
std::getline(students_file, index_no);
std::stringstream(index_no) >> student.index_no;
std::getline(students_file, date_of_birth);
std::getline(students_file, grades);
get_date_from_str(student.day_of_birth, student.month_of_birth, student.year_of_birth, date_of_birth);
get_numbers_from_str(student.grades, grades);
student.avg_grade = calculate_avg(student.grades);
students.push_back(student);
}
for (auto student : students)
{
report_file << std::setw(30) << std::left << student.name
<< std::setw(10) << student.index_no
<< std::setw(20) << date_to_string(student.day_of_birth, student.month_of_birth, student.year_of_birth)
<< std::setw(10) << std::setprecision(2)
<< student.avg_grade << std::endl;
}
}
else
{
std::cout << "Unable to open one of the files!" << std::endl;
}
return 0;
}
First, I think you have complicated your code for both, reading and understanding it, while you have some C++ features that can simplify this part with signs and parsing date and grades.
I have also created struct Student and I have split some of the code into functions.
And, regarding your solution. As someone already mentioned in the comment, fault is in these lines:
while (load >> grades[i])
{
load >> sign;
average += grades[i];
i++;
}
You are 'eating' one character more than you need. And this character is the first character of the name of the second student. Therefore, if you change your code to following, you'll see what I'm talking about:
while (load >> grades[i])
{
if (i != 4) // just a temporary solution, since the first student has 5 grades
load >> sign;
average += grades[i];
i++;
}

Transform c++ class private variables to public

I am a first year student of programming, and I need some help.
I have code with public class but I need to change public to private. And it doesn't work for me. Maybe somebody can help me with some suggestions? Here's my working code with public objects, but I need to private. How can I do that?
This is my class's files:
Klientas.h:
#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <iomanip>
using namespace std;
class Klientas
{
public:
string vardas;
double lesos;
};
#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <iomanip>
using namespace std;
Klipas.h :
class Klipas
{
public:
string produktas;
string grupe;
double trukme;
double krastine1;
double krastine2;
double plotas;
double klipoSekKaina;
double klipoKaina;
};
My code:
Lab_1.cpp
#include "Klipas.h"
#include "Klientas.h"
using namespace std;
//---------------------------------------------
int main() {
setlocale(LC_ALL, "Lithuanian");
Klipas K[100];
int na;
Klientas kl;
// Iš failo fv įveda duomenis į objektų masyvą K(kiek).
ĮvestiDuomenis("Duomenys.txt", K, na);
SpausdintiDuomenis("Rezultatai.txt", K, na);
}
void ĮvestiDuomenis(string fv, Klipas K[], int & kiek) {
ifstream fd ("Duomenys.txt");
fd >> kiek;
fd.ignore();
for (int i = 0; i < kiek; i++) {
getline(fd, K[i].produktas, ','); fd >> ws;
fd >> K[i].grupe;
fd >> K[i].trukme;
fd >> K[i].krastine1;
fd >> K[i].krastine2;
fd >> K[i].klipoSekKaina;
fd.ignore();
}
fd.close();
// cout << "Programa baigė darbą\n";
}
// Objektų masyvo K(kiek) reikšmes spausdina lentele į failą fv
void SpausdintiDuomenis(string fv, Klipas K[], int kiek) {
ofstream fr("Rezultatai.txt", ios::app);
fr.setf(ios::fixed); fr.setf(ios::left);
cout << "Klipų skaičius: " << kiek << endl;
cout << "Klipų sąrašas:\n";
cout << "----------------------------------------------------\n";
cout << "| Produktas | Grupė | Klipo trukmė(s) | 1 Kraštinė(cm) | 2 Kraštinė(cm) | Klipo sekundės kaina(Eur/s) | \n";
cout << "----------------------------------------------------\n";
for (int i = 0; i < kiek; i++) {
cout << "| " << setw(10) << K[i].produktas << "| " << K[i].grupe
<< setprecision(0) << setw(10) << "| " << K[i].trukme << "| " << setw(15) << K[i].krastine1 << "| " << setw(10) << K[i].krastine2 << "| " << setw(10) << K[i].klipoSekKaina << endl;
}
{
cout << "-------------------------------\n";
cout << "Klipo Kava plotas:" << K[0].krastine1*K[0].krastine2 << " " << "cm2" << endl;
cout << "Klipo Obuolys plotas:" << K[1].krastine1*K[1].krastine2 << " " << "cm2" << endl;
cout << "Klipo Sultys plotas:" << K[2].krastine1*K[2].krastine2 << " " << "cm2" << endl;
cout << "-------------------------------\n";
}
string ilg_trukme; // randame kuris klipas yra ilgiausias
if (K[0].trukme > K[1].trukme) {
ilg_trukme = K[0].produktas;
} else if (K[1].trukme > K[2].trukme) {
ilg_trukme = K[1].produktas;
} else {
ilg_trukme = K[2].produktas;
}
cout << "Ilgiausias klipas: " << ilg_trukme << endl;
cout << "-------------------------------\n";
{
K[0].klipoKaina = K[0].trukme * K[0].klipoSekKaina;
K[1].klipoKaina = K[1].trukme * K[1].klipoSekKaina;
K[2].klipoKaina = K[2].trukme * K[2].klipoSekKaina;
cout << "Klipo Kava Kaina:" << K[0].klipoKaina << " " << "Eur." << endl;
cout << "Klipo Obuolys Kaina:" << K[1].klipoKaina << " " << "Eur." << endl;
cout << "Klipo Sultys Kaina:" << K[2].klipoKaina << " " << "Eur." << endl;
cout << "-------------------------------\n";
}
{
string brangiausias_klipas; //randame kuris klipas brangiausias
double br_kl;
Klientas kl;
if (K[0].klipoKaina > K[1].klipoKaina && K[0].klipoKaina > K[2].klipoKaina ) {
brangiausias_klipas = K[0].produktas;
br_kl = K[0].klipoKaina;
} else if (K[1].klipoKaina > K[2].klipoKaina) {
brangiausias_klipas = K[1].produktas;
br_kl = K[1].klipoKaina;
} else {
brangiausias_klipas = K[2].produktas;
br_kl = K[2].klipoKaina;
}
cout << "Brangiausias klipas yra: " << brangiausias_klipas << endl;
cout << "-------------------------------\n";
cout << "Kiek jūs turite pinigų? " << endl; //kliento turimos pajamos
cin >> kl.lesos ;
cout << "-------------------------------\n";
//Randame kuriuos klipus klientas glaėtų įsigyti su savo pajamom
{
if(kl.lesos < K[0].klipoKaina && kl.lesos < K[1].klipoKaina && kl.lesos < K[2].klipoKaina) {
cout << "Jūs negalite nusipikrti nei vieno klipo " << endl;
} else {
if(kl.lesos >= K[0].klipoKaina) {
cout << "Jūs galite nusipirkti klipą " << K[0].produktas << endl;
}
if (kl.lesos >= K[1].klipoKaina) {
cout << "Jūs galite nusipirkti klipą " << K[1].produktas << endl;
}
if (kl.lesos >= K[2].klipoKaina) {
cout << "Jūs galite nusipirkti klipą " << K[2].produktas << endl;
}
}
}
}
}
Your teacher probably wants you to use getters.
In:
class Klipas
{
public:
string produktas;
string grupe;
double trukme;
double krastine1;
double krastine2;
double plotas;
double klipoSekKaina;
double klipoKaina;
};
You want to have access to all these members, but prevent external changes.
So you can change your code to:
class Klipas
{
public:
string GetProduktas() {return produktas;}
string Getgrupe() {return grupe;}
double Gettrukme() {return trukme;}
double Getkrastine1() {return krastine1;}
double Getkrastine2() {return krastine2;}
double Getplotas() {return plotas;}
double GetklipoSekKaina(){return klipoSekKaina;}
double GetklipoKaina() {return klipoKaina;}
private:
string produktas;
string grupe;
double trukme;
double krastine1;
double krastine2;
double plotas;
double klipoSekKaina;
double klipoKaina;
};
and use those getters instead of the objects themselves in your function:
fd >> K[i].Getgrupe();
fd >> K[i].Gettrukme();
fd >> K[i].Getkrastine1();
fd >> K[i].Getkrastine2();
fd >> K[i].GetklipoKaina();
As for setters go, you can either set your values in the constructor, or implement the same way:
public:
void SetProduktas(string prdkt) {produktas = prdkt;}
You can rewrite your class variables to be private and then use getters and setters to modify them.
class C {
private:
int id;
public:
int get_id() { return this->id; }
void set_id(int newId) { this->id = newId; }
};
Or you can make private class inside of another class
class A {
private:
class D {};
};